Why Overrides?
Instead of modifying registered components or restructuring your app, overrides let you:- Replace production implementations with test mocks
- Swap backends (in-memory cache → Redis) without changing tasks
- Feature-flag entire subsystems (real payment → sandbox payment)
- Override third-party dependencies for testing
Basic Usage
Define a component, then override its implementation:Override Syntax Options
Runner provides three ways to create overrides:1. Fluent Builder (Recommended)
2. Shorthand (One-Liner)
3. Helper Function (Classic API)
Overriding Tasks
Overriding Resources
Overriding Middleware
Overriding Hooks
Conditional Overrides
Apply overrides based on environment:Multiple Overrides
Apply multiple overrides at once:Testing Pattern
Create test fixtures with overrides:Override Validation
Overrides must match the original component’s type signature:Overrides vs. Mocks
| Approach | When to Use |
|---|---|
| Overrides | Replace entire implementations while preserving the dependency graph |
| Unit Test Mocks | Pass mock dependencies directly to .run() for isolated tests |
Nested Resource Overrides
Override resources registered in sub-resources:Override Scope
Overrides apply to the entire dependency graph from the registration point down:Best Practices
Keep Test Overrides Separate
Create override definitions in test files, not production code
Use Type Safety
Let TypeScript catch signature mismatches between original and override
Override at the Right Level
Apply overrides in the resource that needs them, not globally
Document Override Purpose
Use
.meta() to explain why an override existsCommon Patterns
Spy Pattern
Partial Override (Resource)
Environment-Specific Overrides
See Also
- Testing - Unit and integration test patterns
- Dependency Injection - Understanding the dependency graph
- Resources - Resource lifecycle and initialization
- Tasks - Task execution and mocking