Simple Injector: a .NET container that makes misconfiguration loud
An easy, flexible, and fast Dependency Injection library that promotes best practice to steer developers towards the pit of success.
At a glance
- What is it?
- Simple Injector is a .NET dependency injection container whose distinguishing feature is container verification, which fails the build of your application if the object graph cannot be constructed, alongside decorator registration and a deliberately small API. It is MIT licensed, the current release is v5.6 from 2026-06-28, and the last push was on 2026-10-09.
- Who is it for?
- Simple Injector fits a .NET team that wants a container small enough to read in an afternoon and a verification step that catches wiring mistakes in the build rather than in production, and it fits a codebase using decorator registration for cross-cutting behaviour. It does not fit a team that needs the built-in features of a larger container, such as scanning assemblies by convention, module systems or a large set of lifestyle built-ins beyond what is registered explicitly.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A container designed to fail loudly at startup
The goal of Simple Injector is to provide .NET application developers with an easy, flexible and fast dependency injection library that promotes best practice to steer developers towards the pit of success, and the wording of that claim is deliberate.
The gap it claims to fill is stated plainly. Many of the existing DI libraries have a big complicated legacy API, or are new and immature and lack features often required by large scale development projects. Simple Injector fills that gap by supplying a simple implementation with a carefully selected but complete set of features that allow you to write highly maintainable applications. The two features it names as setting it apart are decorator registration and container verification.
Container verification is the one that changes how you work. The configuration example in the readme has it as an explicit step:
protected void Application_Start(object sender, EventArgs e)
{
// 1. Create a new Simple Injector container
var container = new Container();
// 2. Configure the container (register)
container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Transient);
container.Register<ILogger, MailLogger>(Lifestyle.Singleton);
container.Register<UserController>();
// 3. Optionally verify the container's configuration.
container.Verify();
// 4. Register the container as MVC3 IDependencyResolver.
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}The step is marked optional in the comment, and it should not be. `Verify()` walks the entire registered object graph and throws if anything cannot be constructed, so a missing registration, an ambiguous registration or an unresolvable dependency becomes a startup exception instead of a NullReferenceException on a rarely used code path in production.
That is the design thesis in one feature. Most containers fail late, on the request that first touches the missing dependency. Simple Injector gives you a way to fail early, on every dependency, in one place.
It is MIT licensed, the default branch is `master`, and the supported platforms are .NET 4.5 and up plus .NET Standard, which the readme lists as including Universal Windows Programs, Mono, .NET Core, .NET 5 and up, and Xamarin.
Lifestyles are explicit, and the object graph is the documentation
The registration API is two overloads and an enum, and the readme walks through what each line does.
`container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Transient)` maps a concrete instance to an interface or base type, and every time you ask the container for an `IUserRepository` it creates a new `SqlUserRepository`.
`container.Register<ILogger, MailLogger>(Lifestyle.Singleton)` registers the second mapping, and only one instance of `MailLogger` will ever be created by the container.
`container.Register<UserController>()` registers a concrete type with no explicit mapping, which lets the container resolve its constructor dependencies itself.
The readme then shows the object graph that results, which is the most useful part of the documentation:
new UserController(
new SqlUserRepository(
logger),
logger);The point being made is that object graphs can become very deep, and that not only `UserController` contains dependencies but so does `SqlUserRepository`, in this case with its own `ILogger` dependency. Simple Injector will not only resolve the dependencies of `UserController` but will build a whole tree structure of any level deep.
That is the reason `Verify()` matters. A graph like the one above, where the same `ILogger` appears twice, is exactly the case where a container's lifetime rules interact in ways that are hard to reason about, and verification is what checks them.
The example code is also modern in a way that shows the library is kept current. The `SqlUserRepository` is written with C# 11 primary constructor syntax, `public class SqlUserRepository(ILogger logger) : IUserRepository`, which means the documentation is regenerated against a current compiler rather than being a decade-old snippet, even though the platform list still mentions .NET 4.5 and Xamarin.
The application integration is the other half of the story, and the readme is clear that it is not automatic for every framework. Some frameworks such as ASP.NET MVC will do the rest for you, while others like ASP.NET Web Forms need a little bit more work, and there is an integration guide with examples for many common application frameworks.
Partial trust and a small repository
Two details in the readme are worth pulling out because they say something about what kind of library this is.
The first is the trust model. Simple Injector is carefully designed to run in partial or medium trust, and it is fast, described as blazingly fast. Partial trust is a .NET Framework concept, a constrained execution environment, and designing for it is a discipline: it rules out things like certain native interop, and it pushes towards a pure managed implementation with no reflection-heavy tricks that would need ReflectionPermission.
The second is the size of the repository. The top-level listing is `.gitattributes`, `.github/`, `LICENSE`, `README.md`, the contributor licence agreement in two formats, `appveyor.bat`, `appveyor.yml` and `src/`. There is no `test/` directory at the top level and no examples directory, which means the tests live inside `src/` alongside the code, and the documentation lives on the website rather than in the repository. The project runs its CI through AppVeyor, with a batch file and a yml file, and the NuGet badge points at the published package.
The contributor licence agreement, in both `.docx` and `.pdf` form, is a detail that tells you something about the project's stage. A contributor licence agreement is a document a maintainer asks contributors to sign or accept when they submit code, typically clarifying that the contribution is licensed under the project's terms and that the maintainer can use it. For a project with a named author and a stable public API, it is a reasonable piece of governance, and the fact that it is committed in two formats rather than kept on a legal website suggests the maintainer wanted it attached to the history.
The documented workflow, and where the hard part actually is
The readme makes a point that is easy to skim past, and it is the one that determines whether adopting this container is worthwhile.
It says that this is all it takes to start using Simple Injector, and that you should design your classes around the SOLID principles and the Dependency Injection pattern, which is actually the hard part, and configure them during application initialization.
That parenthetical is the honest bit. The library is the easy part, and the container is the part you can get wrong in an afternoon. Everything Simple Injector offers, the object graph construction, the lifestyles, the verification, presupposes that you have already decided what your dependencies are and which of them are interfaces. A container cannot do that for you, and the readme is not pretending otherwise.
The example reinforces the point by being a deliberately ordinary application. A `UserController` that depends on `IUserRepository` and `ILogger`, a `SqlUserRepository` that depends on `ILogger` in turn, and the note that by not depending on concrete implementations you can test `UserController` in isolation. The value of dependency injection is described as more than ease of testing: it also enables you to design highly flexible systems that can be completely composed in one specific location, often the startup path, of the application.
That is the case for the container in one sentence. The composition point in the startup path is what you get from a container, and the verification is what keeps that composition point honest as the application grows.
The documentation is organised around that path too. There is a Using section for learning how to configure and use the container, an Integration page for the application framework side, and a quickstart with a More Information section. The project also runs a blog, and the readme points at the website for a high level overview before it dives into the documentation, which is a hint about where to start.
Where Simple Injector is the wrong choice
The first case is a team that wants assembly scanning. Simple Injector's API in the documentation is explicit registration, one call per type. A container that scans assemblies for implementations and registers them by convention saves a lot of lines in a large application, and if that is the style your team has standardised on, an explicit registry is a different workflow even if the runtime behaviour is identical.
The second case is a team that needs a large set of built-in lifestyles and scopes beyond singleton and transient. The library's design is that lifestyles are explicit and few, which is a virtue when you want to reason about lifetimes, and a limitation when you want a scoped or per-request lifestyle that the container provides rather than the framework.
The third case is a team migrating away from a large container. The readme's own framing is that many existing libraries have a big complicated legacy API, and moving to a smaller container means unlearning the configuration idiom, the interception features and the registration extensions your previous container provided. If you are replacing a container for performance reasons rather than for clarity, the migration cost is the dominant factor and it is high.
The fourth is a project where the container must be configured by convention from multiple assemblies with per-assembly lifetimes. That is what a module system is for, and Simple Injector does not present one in the documentation.
A note on the version numbers, since they matter for a library like this. The release history is a steady 5.x line, v5.6 on 2026-06-28, v5.5.2 on 2026-04-26 and v5.5.1 on 2026-04-16, with the last push on 2026-10-09. A 5.x line with releases a couple of months apart is a well-maintained library, and for a container that sits in the startup path of an application, that matters more than any single feature.
Editorial conclusion
Simple Injector fits a .NET team that wants a container small enough to read in an afternoon and a verification step that catches wiring mistakes in the build rather than in production, and it fits a codebase using decorator registration for cross-cutting behaviour. It does not fit a team that needs the built-in features of a larger container, such as scanning assemblies by convention, module systems or a large set of lifestyle built-ins beyond what is registered explicitly. Before you adopt it, read the integration page for your application framework, since the container is framework-agnostic and the integration is where the work is, and put `container.Verify()` in your test suite from the start.
Frequently asked questions
What is Simple Injector and what makes it different from other .NET DI containers?
It is an MIT licensed .NET dependency injection container focused on a small API with a carefully selected feature set. The project names decorator registration and container verification as the two features that set it apart, and it positions itself against libraries with big complicated legacy APIs and against new and immature ones.
What does container.Verify() do in Simple Injector?
It walks the whole registered object graph and throws if any dependency cannot be resolved, so a missing or ambiguous registration becomes a startup failure rather than a runtime error on a rarely used code path. The documentation marks the call as optional, but it is the feature that makes configuration mistakes loud.
Which platforms does Simple Injector support?
The readme lists .NET 4.5 and up, and .NET Standard including Universal Windows Programs, Mono, .NET Core, .NET 5 and up, and Xamarin. It is also designed to run in partial or medium trust.
How do you register a type with a lifestyle in Simple Injector?
Use `container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Transient)` to map an interface to a concrete type with a transient lifestyle, `container.Register<ILogger, MailLogger>(Lifestyle.Singleton)` for a single shared instance, and `container.Register<UserController>()` for a concrete type whose constructor dependencies the container resolves itself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/simpleinjector-simpleinjector)Was this useful?