Quick Reference ("How Do I...")
Your task-focused guide to Aurelia 2's dependency injection system.
Table of Contents
Getting Started
How do I inject a service into my component?
Property injection with resolve():
Constructor injection with @inject:
When should I use resolve() vs @inject?
resolve() vs @inject?resolve()
Prefer property/field injection or want to avoid decorators
Cleaner syntax, works with inheritance, no metadata required
@inject
Prefer explicit constructor injection and immutable dependencies
Constructor clearly documents required services; great for unit tests
static inject
Avoiding decorators entirely
No decorator metadata required
Choosing your style:
Use
resolve()when you want lightweight property injection, when inheriting from framework base classes, or when decorators/emitDecoratorMetadataare unavailable.Use
@injectwhen you want constructor parameters to stay read-only, when your team prefers explicit signatures, or when you need to support tooling that analyzes constructor arguments.static injectremains available for teams that disable decorators entirely.
Property injection example:
How do I create a service?
Heads up: default implementations registered inside
DI.createInterfaceare only consulted when the container has registered the token itself. Resolvers such asoptional(IUserService)orresolve(all(IUserService))will returnundefineduntil you runcontainer.register(IUserService). This matches the runtime behavior in packages/kernel/src/di.ts (container.register(MyStr);comment) and avoids surprising allocations when optional dependencies are missing.
Injecting Dependencies
How do I inject multiple services?
Using resolve():
You can also resolve multiple keys in one call and destructure the tuple result:
This uses the runtime helper defined in packages/kernel/src/di.container.ts to pull each token from the currently active container, which keeps the code concise when a class needs several collaborators.
Constructor injection with @inject:
Using static inject:
How do I make a dependency optional?
Constructor injection with @inject:
How do I inject all implementations of a service?
How do I lazy-load a service?
Creating Services
Which registration helper should I use?
Registration exposes more than singleton vs transient (see packages/kernel/src/di.registration.ts). Pick the helper that matches your lifetime and creation strategy:
Registration.instance(key, value)
Always returns the provided object.
App configuration, external SDK singletons.
Registration.singleton(key, Type)
Lazily creates one instance per container.
Services with shared state (API clients, stores).
Registration.transient(key, Type)
Creates a new instance every time.
Utilities or disposable types.
Registration.callback(key, fn)
Runs the callback on every resolution.
Values that depend on runtime arguments or container state.
Registration.cachedCallback(key, fn)
Runs the callback once per container then caches the result.
Expensive factories that still need manual control of construction.
Registration.aliasTo(original, alias)
Exposes an existing registration under another key.
Provide the same implementation for multiple tokens (mock vs real).
Registration.defer(extension, data)
Defers resource registration until a dedicated registry handles it.
Template preprocessors and conventions (used by the HTML preprocessor for CSS modules).
Combine these helpers with Aurelia.register(...) or container-local register(...) calls wherever you wire up services.
How do I create a simple service?
How do I inject dependencies into my service?
Using resolve() (recommended):
Constructor injection with @inject:
How do I create a service without auto-registration?
Then register manually:
How do I use a class directly without an interface?
Note: For better testability and decoupling, prefer using DI.createInterface().
Service Lifetimes
What are the different service lifetimes?
Singleton
One instance per container
Services with shared state, API clients, configuration
Transient
New instance every injection
Stateless utilities, factories, disposable objects
How do I create a singleton service?
Why singleton? Auth state should be shared across the entire application.
How do I create a transient service?
Why transient? Each logger should have its own timestamp.
How do I force a new instance regardless of registration?
Or with constructor:
Advanced Injection
How do I inject into properties (not constructor)?
Why property injection?
Works with inheritance (constructor calls can be tricky)
Cleaner when extending framework classes
Modern with
resolve()
How do I create a factory for my service?
How do I publish my own scoped context?
Use InstanceProvider when you need to expose a value that should be resolved exactly as-is by descendants. Aurelia uses the same primitive to wire controllers, hydration contexts, and router state into child scopes (see packages/runtime-html/src/templating/controller.ts and packages/router/src/route-context.ts).
Call
registerResolverwith the provider soresolve(IFeatureContext)returns the prepared value.The optional third argument (
true) tells the container to dispose the provider automatically when the scope goes away.You can replace the value later via
provider.prepare(newValue)to update the scoped instance.
How do I scope a service to a component?
How do I inject the last registered instance?
Useful when you have multiple registrations and want the override:
How do I plug in custom factories or transformers?
When the built-in lifetime helpers are not enough, register your own factory for a key. This is how Aurelia supports interface tokens whose concrete type needs extra inputs (see packages/tests/src/1-kernel/di.get.spec.ts for working examples).
container.registerFactory(key, factory)ties a token to a custom factory. For interface tokens you can cast the interface toConstructableexactly like the runtime tests do. Insideconstructyou can callcontainer.getFactory(SomeClass).construct(...)to reuse Aurelia's dependency calculation.container.registerTransformer(key, transformer)lets you wrap or mutate instances after construction—perfect for logging proxies, caching, or feature flags. The container implementation keeps the transformer list per key (packages/kernel/src/di.container.ts:305-330, 664-668).
CachedReportService in the example is any decorator you want to apply—it simply receives the just-created ReportService and returns the wrapped instance you want the container to hand out.
If you simply need one-off construction hooks, prefer Registration.callback/Registration.cachedCallback. Reach for registerFactory only when you need full control over how and when instances are created.
Container Management
How do I configure a container?
DI.createContainer() accepts an optional configuration object that maps directly to the runtime IContainerConfiguration (packages/kernel/src/di.container.ts). Use it to change inheritance and default registration strategy:
inheritParentResources copies the parent container’s resource registrations (custom elements, attributes, value converters, etc.) into the child. Shadow DOM features or micro-frontends can opt in so they see exactly what the parent registered without falling back to the app root.
defaultResolver controls how plain classes are auto-registered when you first resolve them.
DefaultResolver.singleton(the default) caches one instance per container; switching toDefaultResolver.transientensures everyresolve(SomeClass)call returns a fresh instance. If you want to force explicit registrations, useDefaultResolver.noneso the container throws whenever you resolve an unknown class (great for large teams that prefer auditability).
Child containers can also pass { inheritParentResources: true } to createChild(...) for one-off scopes that need the same behavior.
How do I create a custom container?
How do I create a child container?
Use cases:
Feature modules with their own services
Testing with mocked dependencies
Multi-tenant applications
How do I register multiple implementations?
How do I register instances directly?
Use cases:
Configuration objects
External libraries
Pre-initialized objects
How do I check or override an existing registration?
The container exposes inspection APIs so you can detect whether something is registered and optionally swap it out at runtime (see IContainer.has/getResolver in packages/kernel/src/di.ts).
container.has(key, searchAncestors)lets you check whether a key exists locally or anywhere up the parent chain.container.getResolver(key, /*autoRegister*/ false)gives you the current resolver without triggering auto-registration, so you can inspect or replace it.registerResolveraccepts anyIResolver(includingInstanceProvider) and an optionalisDisposableflag to clean up automatically.
How do I deregister a service?
Warning: Use sparingly - can cause issues if other services depend on it.
Testing
How do I mock services for testing?
How do I test a service with dependencies?
Common Patterns
How do I create a configuration service?
Use in services:
How do I create a service with initialization logic?
Initialize on app start:
How do I implement the Service Locator pattern?
Note: Prefer constructor/property injection over service locator for better testability.
How do I create a plugin system?
Troubleshooting
Error: "Cannot resolve key"
Problem: DI container can't find a registration for your service.
Solutions:
Forgot to create interface token:
Interface not imported/registered:
Manual registration missing:
Error: "Cyclic dependency"
Problem: Service A depends on Service B, which depends on Service A.
Solution 1 - Use lazy injection:
Solution 2 - Refactor to break cycle:
resolve() returns undefined
Problem: Using resolve() outside of DI context.
Solutions:
In components:
resolve()works anywhereIn plain classes: Must be injected or instantiated by DI
In static methods: Can't use
resolve()- use injection
TypeScript errors with resolve()
resolve()Problem: Type inference not working with resolve().
Solution: Explicitly specify type:
Service isn't a singleton (getting different instances)
Problem: Service registered as transient or created with new.
Solutions:
Check registration:
Don't create with
new:
Constructor injection order mismatch
Problem: Parameters don't match @inject decorator order.
Complete Documentation
DI Overview - Comprehensive concepts guide
Creating Services - Service creation patterns
Resolvers - Advanced injection control
What is DI? - DI fundamentals
DI Diagrams - Visual architecture guide
Essentials Guide - Quick start guide
Last updated
Was this helpful?