Reflex attaches a container to Unity scenes, and the setup is mostly file placement
Minimal dependency injection framework for Unity
At a glance
- What is it?
- Reflex is a Unity dependency injection framework built around installers that register into a ContainerBuilder, with a scene-level container that lives and dies with the scene. A source generator replaces most runtime reflection, which is what lets it run under IL2CPP.
- Who is it for?
- Adopt Reflex if your Unity project has grown past static wiring and you want scene-scoped lifetimes without hand-rolling a bootstrap, since AOT compatibility removes the usual objection to reflection-based containers. Do not adopt it for a small project where the container would be larger than the graph.
- 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 12 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 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Getting started is a prefab placement exercise
The setup path in the README is a twenty-two-step walkthrough, and most of the steps are about where files sit in the Unity project rather than what code they contain.
Installation has three routes. Unity Package Manager takes a git URL, in this case https://github.com/gustavopsantos/reflex.git?path=/Assets/Reflex/#14.4.0, entered through the + button and Add package from git URL. OpenUPM installs with `openupm install com.gustavopsantos.reflex`. Or you download a .unitypackage from the releases page and import Reflex.X.X.X.unitypackage.
Then the structure. You write a RootInstaller MonoBehaviour implementing IInstaller, whose InstallBindings method receives a ContainerBuilder.
public class RootInstaller : MonoBehaviour, IInstaller
{
public void InstallBindings(ContainerBuilder builder)
{
builder.RegisterValue("Hello");
}
}You right-click any folder and choose Create then Reflex then RootScope. The README notes it can go anywhere, because RootScope is strongly referenced by ReflexSettings and does not need to be inside a Resources folder.
The settings object is where the placement rules bite. Create a directory at Assets/Resources, right-click it, and choose Create then Reflex then Settings. ReflexSettings should always be created directly inside Resources with no subfolder, and you add the RootScope prefab to its RootScopes list. Then the consumer is a plain MonoBehaviour with an injected field.
public class Greeter : MonoBehaviour
{
[Inject] private readonly IEnumerable<string> _strings;
private void Start()
{
Debug.Log(string.Join(" ", _strings));
}
}One detail in that line is worth noting: the field is IEnumerable<string>, not string. A contract collection resolves everything bound to that type in scope, which is how a scene installer adds a second string to the root one and the consumer sees three.
Scene scopes are the reason to use this instead of a plain container
Inside a scene you create a scene scope from the Hierarchy context menu, add an installer component to it, and the installer contributes to that scene's container.
public class GreetInstaller : MonoBehaviour, IInstaller
{
public void InstallBindings(ContainerBuilder builder)
{
builder.RegisterValue("World");
}
}So the root installer contributes Hello, the scene installer contributes World, and the walkthrough ends with three instances implementing string once a third binding is added. The contract collection in the Greeter sees all of them, which is the mechanism that makes the tree useful: a scene can contribute without knowing who consumes it.
There is also a way to contribute to a scene container you are not authoring. ContainerScope.OnSceneContainerBuilding is an event you subscribe to before loading a scene, and the handler receives the ContainerBuilder of the scene that is currently building.
ContainerScope.OnSceneContainerBuilding += InstallExtra;
UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Greet").completed += operation =>
{
ContainerScope.OnSceneContainerBuilding -= InstallExtra;
};The unsubscription on completion is the part to copy. The README gives separate handlers for scenes loaded without Addressables and scenes loaded with Addressables, because the completion event differs between SceneManager.LoadSceneAsync and Addressables.LoadSceneAsync. If you subscribe and do not unsubscribe, a later scene load picks up your bindings too, which is a bug that appears one scene later than you wrote it.
Values registered with RegisterValue are always singletons, which the README points out twice in the examples.
The source generator is what makes IL2CPP a non-issue
The performance claims are comparative and should be read that way: up to 414% faster than VContainer and up to 800% faster than Zenject, and up to 28% less allocation than VContainer and up to 921% less than Zenject. Those are the README's own numbers and we have not run them.
The mechanism behind them is stated in the overview list, and it is the same mechanism that removes the usual objection to a reflection-based container. Reflex implements a modern Roslyn source generator, with a Reflex.Generator project at the root of the repository, and the generator's job is to minimise reflection at injection time.
The AOT point follows from that. The README states there is basically no runtime Emit, so it works fine on IL2CPP builds, and it carries a footnote marker to the scripting restrictions section. For a Unity project that ships to console or mobile with IL2CPP, this is the deciding constraint: a container that uses runtime Emit is unusable on those targets, and this one is not.
Two other properties are listed as design decisions rather than features. The container is immutable, which gives thread safety without locks and predictable behaviour. And there is a contract table, which is what lets you ask a container for everything implementing an interface, as in container.All<IDisposable>, rather than only for a concrete type.
The documented platform list includes iOS, Android, Windows, Mac and Linux, PS4 and PS5, the Xbox families, and WebGL. Unity 2021 or newer is the stated floor.
Where Reflex is the wrong choice
The first case is a small project. The container is a dependency, and a dependency with installers, scopes, a settings prefab and a generator is a lot of structure for a scene with three objects talking to each other. ScriptableObject singletons and direct references are the smaller answer there.
The second is the AOT story if you need runtime flexibility the generator cannot cover. The source generator knows your types at compile time, which is why it is fast and why it works on IL2CPP, and the trade is that anything resolved dynamically at runtime is outside what the generator could precompute. The README has sections on attributes, manual injection and extensions, which are the escape hatches, but they exist because the generated path does not cover those cases.
The performance benchmarks name VContainer and Zenject as alternatives. Compared with a hand-rolled service locator, Reflex gives you compile-time bindings and a scene graph, and takes on the file placement rules described above.
The alternative for teams who want DI without Unity specifics is using a plain.NET container and a thin Unity wrapper, which gives you the mature tooling of that ecosystem at the cost of writing the scene integration yourself.
On versions, the recent tags are 14.4.0 on 2026-10-10, 14.3.1 in June 2026 and 14.3.0 in March 2026, the last push to the repository was on 2026-10-10, and the licence is MIT.
Editorial conclusion
Adopt Reflex if your Unity project has grown past static wiring and you want scene-scoped lifetimes without hand-rolling a bootstrap, since AOT compatibility removes the usual objection to reflection-based containers. Do not adopt it for a small project where the container would be larger than the graph. Before you start, note that ReflexSettings must sit directly in Assets/Resources and RootScope must be listed in it, or nothing resolves.
Frequently asked questions
How do I install Reflex in Unity?
Add the git URL https://github.com/gustavopsantos/reflex.git?path=/Assets/Reflex/#14.4.0 through the Unity Package Manager, install it with openupm install com.gustavopsantos.reflex, or import the .unitypackage from the releases page.
Does Reflex work with IL2CPP builds?
Yes. The README states there is basically no runtime Emit because Reflex uses a Roslyn source generator, and that this makes it work fine on IL2CPP builds. It lists iOS, Android, PlayStation, Xbox and WebGL among the compatible platforms.
Where do I put ReflexSettings in a Unity project?
Create Assets/Resources, right-click it and choose Create then Reflex then Settings. The README states ReflexSettings should always be created directly inside Resources with no subfolder, and you add the RootScope prefab to its RootScopes list.
How do I contribute bindings to a scene I am loading?
Subscribe to ContainerScope.OnSceneContainerBuilding before loading, and unsubscribe in the completion handler. The README gives separate handlers for SceneManager.LoadSceneAsync and for Addressables.LoadSceneAsync, and the unsubscription is what stops your bindings from leaking into later scene loads.
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/gustavopsantos-reflex)