Engine-agnostic dependency-injection container for .NET. Pure C#, zero runtime dependencies.
Quick start · Getting started · Containers · Aliasing · Analyzers · Benchmarks
Buttr is a lightweight dependency-injection framework. The Core library is engine-agnostic — it targets netstandard2.1 and has no dependency on Unity, Godot, or any other engine. Game-engine integrations live in sibling repos that vendor these DLLs and add engine-specific glue on top.
Design priorities, in order:
- Zero-allocation on the hot path. Resolved singleton
Get<T>is 0 B allocated, measured. - API first. The builder chain is what Buttr was designed around — short, fluent, obvious.
- Low barrier to entry. If you've used any DI container, you already know the shape.
| Assembly | Purpose |
|---|---|
Buttr.Core |
DI container, builders, resolvers, lifetimes, scopes, Application<T> |
Buttr.Injection |
[Inject] marker attribute + InjectionProcessor registry — consumed by engine-side source generators |
Buttr.Core.Analyzers |
Roslyn analyzers + fixers, bundled in the Buttr.Core NuGet at analyzers/dotnet/cs/ |
using Buttr.Core;
// 1. Build a container
var builder = new DIBuilder();
builder.Resolvers.AddSingleton<IAuthService, AuthService>();
builder.Resolvers.AddTransient<RequestHandler>();
var container = builder.Build();
// 2. Resolve
var auth = container.Get<IAuthService>();
// 3. Bulk-resolve every implementation of an interface
builder.Resolvers.AddSingleton<StartupCommand>().As<ICommand>();
builder.Resolvers.AddSingleton<ShutdownCommand>().As<ICommand>();
foreach (var cmd in container.All<ICommand>()) cmd.Run();
container.Dispose();See Getting Started for a full walk-through, Containers for the DIContainer / ScopeContainer / Application distinction, and Aliasing for .As<>() and All<T>() patterns.
| Container | Get<T> singleton (resolved) |
Get<T> transient (3 deps) |
All<T> (5 matches) |
|---|---|---|---|
| DI | 13 ns, 0 B | 64 ns, 40 B | 49 ns, 0 B |
| Scope | 9 ns, 0 B | 64 ns, 40 B | 48 ns, 0 B |
| Application (static) | 3 ns, 0 B | 58 ns, 40 B | 71 ns, 0 B |
Transient allocation equals the new instance — TryResolve adds no visible overhead. All<T> uses a struct enumerator so foreach is zero-allocation.
Reproducing and full reports in Docs/Benchmarks/.
dotnet add package Buttr.Core
Brings in the Buttr.Core assembly plus Buttr.Core.Analyzers shipped at analyzers/dotnet/cs/. Add Buttr.Injection separately if you need the [Inject] marker + InjectionProcessor registry (source generators on the consumer side consume this):
dotnet add package Buttr.Injection
UPM doesn't speak NuGet, so this repo also ships a small UPM package at package/ that vendors the same Core DLLs. Add to your project's Packages/manifest.json:
"com.crumpetlabs.buttr": "https://github.com/Crumpet-Labs/Buttr.Core.git?path=package"Pin a specific version with #<tag>, e.g. #1.3.2. The package places Buttr.Core.dll and Buttr.Injection.dll under Runtime/Lib/ with minimal meta files — Unity handles the rest.
For the Unity-specific glue (MonoBehaviour/ScriptableObject wiring, scene walker, [Inject] source generator), install the companion Buttr.Unity package alongside:
"com.crumpetlabs.buttr.unity": "https://github.com/Crumpet-Labs/Buttr.Unity.git?path=Assets/Plugins/Buttr"Buttr.Unity also vendors the Core DLLs, so use either the Core UPM package or Buttr.Unity — not both, or Unity will complain about duplicate assembly imports.
Engine-specific bridges live in their own repos and vendor the Core DLLs. Pattern: vendor the DLLs, add an engine-specific source generator (or runtime injector) that wires [Inject]-decorated fields at the engine's appropriate lifecycle hook.
Currently shipping:
- Buttr.Unity (
com.crumpetlabs.buttr.unity) — MonoBehaviour / ScriptableObject wiring, scene walker,[Inject]source generator.
dotnet build -c Release
dotnet test
Semantic — minor bumps for additive features (aliasing in 1.1, analyzers in 1.2, zero-alloc All<T> in 1.3), majors reserved for binary-breaking changes.
See Docs/Contributing.md. Short version: keep comments out of code, discuss architectural changes first, and tests must stay green.
MIT — see LICENSE.md.