@inferdi/express
v6.1.0
Published
Express request-scope middleware for InferDI.
Maintainers
Readme
@inferdi/express
Your Express app. A compiler-checked service graph.
Typed request scopes and response-aware cleanup, delivered as Express middleware.
Get started · InferDI · All integrations
Read the docs in your language
English · 中文 · 日本語 · Español · Русский · Deutsch · Français
InferDI is a TypeScript dependency injection container that checks how your services fit together at compile time. @inferdi/express brings that graph to Express 5 with one scope per request on req.di. Keep service wiring explicit and let middleware manage request lifetimes, including responses that stream beyond the handler.
The graph is the type. Built for speed.
Catch broken wiring while you code. Each registration records service types, dependencies and lifetimes in the container’s type. TypeScript rejects missing keys, duplicate registrations, incompatible constructor arguments and declared singleton dependencies on scoped services. Async dependencies and required scope inputs also determine which services are ready to resolve. Refactor a constructor and your editor points to affected registrations.
Keep your business logic yours. Choose implementations explicitly where you assemble the application. Services receive ordinary constructor or function arguments, with no InferDI imports, decorators or metadata. You can test them directly and keep business policy independent of the framework and container. Reusable modules, lazy resolution and typed overrides support composition as the application grows.
Fast resolution, compact core. InferDI core has zero runtime dependencies, an enforced budget under 3 KiB gzip and a single Map.get() fast path for cached services. In the recorded core cached-singleton benchmark, default InferDI is 1.76× to 13.05× faster than the compared containers, with runtime checks enabled. These are core operation measurements; adapter overhead and application performance depend on the workload. Explore the benchmarks.
Static checks cover the declared graph within TypeScript’s limits; casts can bypass them and structurally identical dependency types remain interchangeable.
Why use it with Express
- Your types in every handler: declaration merging gives
Express.Requestyour concrete scope type and preserves typed service resolution. - Scopes ready before routing: sync or async hooks create and initialize request services before handing control to Express.
- Streaming-aware cleanup: scopes dispose when the Node response finishes or closes; normal stream responses need no special skip.
- Ownership you control: customize disposal and error reporting, or retain a scope for work beyond the HTTP response.
- Fits existing Express code: integrate through middleware while keeping domain services independent of Express and InferDI.
Lifecycle essentials
Automatic cleanup follows the response’s finish or close event. Setup failure releases the unfinished scope and passes only the original error to next. Cleanup failures go to onDisposeError or console.error.
skipInferdiDispose(req) transfers disposal to application code. That ownership remains yours if a route later fails: Express callback middleware cannot observe a handled downstream exception at cleanup time. Dispose retained scopes from your own completion and error paths.
Setting autoDispose to false, or returning false from its predicate, also transfers ownership. The middleware never disposes the root container. The guide covers streaming, background work and the handled-error limitation.
Get started
Express 5 · Node.js 18+ · TypeScript 5.2+ · InferDI 6. TypeScript applications also need @types/express.
Available on npm and JSR, alongside @inferdi/inferdi.
Installation, request declaration merging, lifecycle options, streaming and error ownership are covered in the guide.
GitHub · Report an issue · MIT license
A single skipInferdiDispose(req) call applies to every InferDI middleware instance on that request. Application code must retain and dispose every scope; req.di exposes the scope assigned by the last middleware.
