Documentation / zerotal / index / Container
Class: Container
Defined in: packages/core/src/container/Container.ts:56
Registers and resolves bindings, with auto-wiring, scopes, and contextual overrides.
The container is the framework's IoC core. Register how a token is built with
bind (transient), singleton, scoped, or value,
then resolve it with make. Classes with declared dependencies
(@inject()) are auto-wired without an explicit binding.
Remarks
Resolution is async-first: prefer make everywhere and reserve makeSync for Facade accessors where the singleton has already been pre-resolved. Scoped bindings only resolve inside a request scope opened by runScoped; resolving one elsewhere throws ScopedOutsideRequestError.
Example
class Config {}
class Db {}
const container = Container.createEmpty();
container.bind(Db, () => new Db()); // new instance each make()
container.singleton(Config, () => new Config()); // built once, cached
container.value("appName", "zerotal"); // pre-built value
const db = await container.make(Db);
const config = await container.make(Config);
Constructors
Constructor
new Container():
Container
Returns
Container
Binding
bind()
bind<
T>(token,factory):this
Defined in: packages/core/src/container/Container.ts:84
Register a transient binding — the factory runs on every resolution.
Type Parameters
T
T
Parameters
token
BindingToken<T>
factory
Factory<T>
Returns
this
Example
container.bind(Uuid, () => new Uuid(crypto.randomUUID()));
const a = await container.make(Uuid);
const b = await container.make(Uuid); // a !== b
singleton()
singleton<
T>(token,factory):this
Defined in: packages/core/src/container/Container.ts:104
Register a singleton binding — resolved once and cached for the process lifetime.
Type Parameters
T
T
Parameters
token
BindingToken<T>
factory
Factory<T>
Returns
this
Remarks
The factory receives the container so it can resolve its own dependencies.
Concurrent first resolutions share a single in-flight promise, so the
factory runs exactly once even under parallel make() calls.
Example
container.singleton("config", (c) => new ConfigManager());
const config = await container.make("config"); // same instance every time
scoped()
scoped<
T>(token,factory):this
Defined in: packages/core/src/container/Container.ts:123
Register a scoped binding — resolved once per request scope.
Type Parameters
T
T
Parameters
token
BindingToken<T>
factory
Factory<T>
Returns
this
Remarks
Resolving a scoped token outside a request scope (see runScoped) throws ScopedOutsideRequestError.
value()
value<
T>(token,instance):this
Defined in: packages/core/src/container/Container.ts:137
Register an already-constructed value under token.
Type Parameters
T
T
Parameters
token
BindingToken<T>
instance
T
Returns
this
Remarks
Value bindings are the only kind (besides an already-resolved singleton) that makeSync can return.
alias()
alias(
from,to):this
Defined in: packages/core/src/container/Container.ts:153
Make resolving from resolve to instead. Alias chains are followed transitively.
Parameters
from
unknown
to
unknown
Returns
this
Example
container.singleton(FileLogger, () => new FileLogger());
container.alias("log", FileLogger);
const log = await container.make("log"); // resolves FileLogger
for()
for<
C>(consumer):ContextualBindingBuilder<C>
Defined in: packages/core/src/container/Container.ts:190
Begin a contextual binding so consumer receives a tailored dependency.
Type Parameters
C
C
Parameters
consumer
BindingToken<C>
Returns
ContextualBindingBuilder<C>
Example
// ReportService gets a FixedClock; everyone else gets the default Clock.
container.singleton(Clock, () => new SystemClock());
container.for(ReportService).give(Clock, () => new FixedClock());
defer()
defer(
token,provider):this
Defined in: packages/core/src/container/Container.ts:203
Defer a provider so it boots lazily the first time token is resolved.
Parameters
token
unknown
provider
(app) => unknown
Returns
this
Remarks
Booting the provider (its onRegister/onBooting/onBooted hooks) only
runs when Container._app is set, i.e. inside a real application boot.
createEmpty()
staticcreateEmpty():Container
Defined in: packages/core/src/container/Container.ts:603
Create a fresh container with no bindings registered.
Returns
Container
Lifecycle hooks
resolving()
resolving<
T>(token,hook):this
Defined in: packages/core/src/container/Container.ts:172
Register a hook fired with each freshly constructed instance of token.
Type Parameters
T
T
Parameters
token
BindingToken<T>
hook
(instance) => void
Returns
this
Remarks
The hook runs after construction on every fresh instance — so once per process for a singleton, and on each resolution for a transient. It does not fire for an already-cached singleton or value.
Example
container.resolving(Mailer, (mailer) => mailer.setFrom("noreply@example.com"));
Other
registry
registry:
Map<unknown,Binding<unknown>>
Defined in: packages/core/src/container/Container.ts:58
Resolution
make()
make<
T>(token,consumer?):Promise<T>
Defined in: packages/core/src/container/Container.ts:229
Resolve a binding asynchronously. This is the primary resolution method. Always use this over makeSync() unless you have pre-resolved the singleton during onBooting().
Type Parameters
T
T
Parameters
token
BindingToken<T>
The class, abstract class, or registry key to resolve.
consumer?
unknown
Optional resolving consumer, used to apply a contextual override registered via for.
Returns
Promise<T>
The resolved instance.
Throws
When no binding exists and the token cannot be auto-wired.
Throws
When resolving token re-enters itself through its dependency chain.
Throws
When token is a scoped binding resolved outside a request scope.
Example
const users = await container.make(UserService);
const config = await container.make("config");
makeSync()
makeSync<
T>(token):T
Defined in: packages/core/src/container/Container.ts:243
Resolve a binding synchronously. Only works for: value bindings, and singleton bindings already resolved. Throws SyncResolutionError for everything else. Use this exclusively in Facade accessors — after onBooting() has run.
Type Parameters
T
T
Parameters
token
BindingToken<T>
Returns
T
Throws
When no binding is registered for the token.
Throws
When the binding is a not-yet-resolved singleton, or is transient/scoped (which cannot resolve synchronously).
build()
build<
T>(ctor):Promise<T>
Defined in: packages/core/src/container/Container.ts:279
Construct a class by auto-wiring its declared dependencies (@inject()),
bypassing any registered binding for that token.
Used by the app/services convention to build a fresh instance inside a
singleton/scoped factory without the factory shadowing auto-wiring.
Type Parameters
T
T
Parameters
ctor
(...args) => T
Returns
Promise<T>
Throws
When the class's dependency graph contains a cycle.
forget()
forget(
token):boolean
Defined in: packages/core/src/container/Container.ts:289
Remove a binding. Returns true if a binding existed for the token.
Follows the alias chain so forget(alias) removes the canonical binding.
Parameters
token
Returns
boolean
bound()
bound(
token):boolean
Defined in: packages/core/src/container/Container.ts:302
Report whether a binding — or a deferred provider — exists for token,
without constructing anything. Follows the alias chain.
Used by the boot-time doctor to verify that every token a provider names in
static provides is actually wired.
Parameters
token
Returns
boolean
isDeferred()
isDeferred(
token):boolean
Defined in: packages/core/src/container/Container.ts:314
Report whether token resolves through a deferred provider (booted lazily
on first make()), as opposed to an eagerly-registered binding. Follows the
alias chain.
Parameters
token
Returns
boolean
tryMake()
tryMake<
K>(token):ContainerBindings[K] |undefined
Defined in: packages/core/src/container/Container.ts:587
Attempt to resolve a binding synchronously. Returns undefined instead of throwing if the key is not registered. Used by providers to check whether CommandRunner exists (it only does in console mode, not web mode).
Type Parameters
K
K extends keyof ContainerBindings
Parameters
token
K
Returns
ContainerBindings[K] | undefined
Scopes
runScoped()
runScoped<
T>(callback):Promise<T>
Defined in: packages/core/src/container/Container.ts:541
Run callback inside a fresh request scope.
A new ScopedResolver is created for the duration of the call and stored
in AsyncLocalStorage so every container.make() for a scoped binding
resolves against this scope — even across await boundaries and even
when multiple requests are in flight concurrently. The resolver is flushed
(cache cleared) in a finally block, and the ALS entry is garbage-collected
automatically when the async context exits. There is no shared mutable
state on the container and therefore no possibility of cross-request leaks.
Type Parameters
T
T
Parameters
callback
(scoped) => Promise<T>
Receives the resolver so the caller can pass it to
HttpContext (and therefore to afterResponse() hooks).
Returns
Promise<T>
Example
await container.runScoped(async (scoped) => {
// scoped bindings resolve to per-request instances inside here
const session = await container.make(RequestSession);
return handle(session);
});
createScopedResolver()
createScopedResolver():
ScopedResolver
Defined in: packages/core/src/container/Container.ts:553
Create a bare ScopedResolver without entering an ALS context.
Useful in unit tests that call scoped.resolve() directly and do not
need container.make() to route through the ALS store.