What is Alloy?
Alloy is a build-time dependency injection toolkit for TypeScript applications using Vite, webpack, or Rspack.
It scans your code at build time to build a dependency graph and generates a DI container, which is then available to your application as a virtual module. This approach minimizes runtime overhead, avoids reflect-metadata, and provides a clean, declarative API for managing your services.
Why Alloy?
Most TypeScript DI frameworks configure the container at runtime. They resolve the graph while your app runs, usually lean on reflect-metadata (a global polyfill plus emitDecoratorMetadata), and only surface wiring mistakes when a code path is first hit.
Alloy moves that work to build time. The plugin reads your @Injectable classes, constructs the dependency graph during the build, and generates the container as code. That shift produces properties runtime containers can't easily match:
- Errors surface at build time, not in production. Circular dependencies, duplicate registrations, and captive-dependency leaks (a longer-lived service depending on a shorter-lived one — e.g. a singleton on a transient) fail the build — not a request three weeks later.
- Zero runtime reflection. No
reflect-metadata, noemitDecoratorMetadata, no global polyfill — yet services are still discovered automatically, not hand-registered one by one. - Bundler-native lazy loading.
Lazy(() => import('./Heavy'))makes a dependency a real dynamic-import boundary, so your DI graph and your bundler's chunk graph are the same graph. DI participates in code-splitting instead of fighting it. - A minimal, tree-shakeable runtime. The generated container is little more than a map of factories; opt-in features drop out entirely when unused.
- Type safety without magic. Dependencies are declared as strongly-typed tuples and checked against constructors at compile time, and generated
ServiceIdentifiers stay stable across minification and code-splitting. - A visible graph. Because the graph is known at build time, Alloy can emit a Mermaid diagram of your services.
The trade-off is that Alloy is a build-time tool: it relies on a bundler plugin and resolves asynchronously to support lazy imports. In exchange you get safety and bundle-awareness that runtime containers fundamentally can't offer.