# injecute > Type-safe, decorator-free dependency injection container for TypeScript. This documents injecute 1.x. - Services are registered with explicit dependency keys: `addSingleton(key, factoryOrClass, [dependencyKeys])`. - Classes are detected and constructed with `new`; use `construct(Class)` for ES5-compiled or bound classes. - `fork()` creates a child container; `fork({ isolated: true })` makes overrides reach the whole graph (tests). A fork for one unit of work (a session, a request, a transaction, a job) is a scope: its services may depend on root services, never the reverse. - Request data (trace id, tenant, user) goes in a context accessor backed by AsyncLocalStorage, registered first in the root container. - Modules are plain functions over `ServiceRegistry<{ …what they need }>` applied with `extend()`. - Errors are `InjecuteError` with a stable `code`; each code has a page under /errors/. ## Table of Contents ### Start - [Getting started](https://masyaka.github.io/injecute/guide/getting-started.md): Install injecute, register services with explicit dependency keys, and resolve them with full types. - [Registering services](https://masyaka.github.io/injecute/guide/registration.md): Lifetimes (singleton, transient, instance), dependency keys, optional dependencies, aliases, decoration and classes. - [Containers, forks and modules](https://masyaka.github.io/injecute/guide/containers.md): Forks, isolated forks for tests, modules with extend(), and namespaces. - [Structuring an app](https://masyaka.github.io/injecute/guide/app-structure.md): Keep the web framework out of the application core, and keep the container wiring in files of its own. What each gives you, what it costs, and when to do otherwise. - [Extension points with tags](https://masyaka.github.io/injecute/guide/tags.md): Let modules contribute services to an extension point (routes, commands, health checks, plugins) with createTag(), and give the owner all of them as a typed array with collect(). - [Lifecycle and dispose](https://masyaka.github.io/injecute/guide/lifecycle.md): Release connections and other resources with dispose() and await using, in reverse creation order. - [Startup and shutdown](https://masyaka.github.io/injecute/guide/startup-shutdown.md): Lifecycle hooks with createLifecycle() and startLifecycle(): modules start work in stages at startup (consumers, servers, subscriptions) and stop gracefully in reverse. ### How-to - [Testing](https://masyaka.github.io/injecute/guide/testing.md): Replace dependencies in tests with isolated forks, clean up with await using, and assert error codes. - [Middlewares and events](https://masyaka.github.io/injecute/guide/middleware-events.md): Wrap resolution with middlewares (tracing, fallbacks, deprecations, guards, test doubles) and observe containers with events. - [Custom registration](https://masyaka.github.io/injecute/guide/custom-registration.md): Build your own way to register services (files in a directory, wiring generated from files, standard decorators) as a module applied with extend(), what the compiler still checks, and when a middleware fits instead. - [Building an SDK](https://masyaka.github.io/injecute/guide/sdk.md): A platform SDK that other teams install, built on a hidden container. Consumers get a plain object with lazy services, start and stop, plugins that replace, decorate or extend its services, and a test kit. - [Async services](https://masyaka.github.io/injecute/guide/async.md): Services created asynchronously, in a DIContainer with defer() or in an AsyncDIContainer that awaits every dependency. - [Request context](https://masyaka.github.io/injecute/guide/request-context.md): Give every service the trace id, tenant and user of the current request with a context accessor backed by AsyncLocalStorage. - [Scoped state](https://masyaka.github.io/injecute/guide/request-state.md): State that belongs to one unit of work (a session, a request, a transaction, a job) - scopes with their own services, and patterns that keep every service in the root (arguments, a unit of work, a context, one instance per context, resources released at the end, a strategy per tenant), with a table for choosing. - [TypeScript](https://masyaka.github.io/injecute/guide/typescript.md): How injecute types containers, how to type modules and consumers, what the errors look like, and supported TypeScript versions. - [Without a build step](https://masyaka.github.io/injecute/guide/no-build.md): Use injecute directly in browsers, Deno and Bun, from npm, JSR or a CDN. - [Recipes](https://masyaka.github.io/injecute/guide/recipes.md): A unit of work per operation, a scope, configuration-driven implementations, feature modules, a module's private services, an SDK for other teams, sharing services between containers. - [Using injecute with AI agents](https://masyaka.github.io/injecute/guide/ai-agents.md): Point coding agents at the docs of the installed version, install the Agent Skill, and use llms.txt or Context7. ### Frameworks - [Frameworks](https://masyaka.github.io/injecute/frameworks.md): How injecute fits into a web framework (the composition root, routes from modules, request context, startup and shutdown, tests), with pages for Express, Fastify, Hono, Next.js, GraphQL, React, Vue, Solid and NestJS users. - [Express](https://masyaka.github.io/injecute/frameworks/express.md): Use injecute with Express — typed services in handlers without app.locals, routers contributed by feature modules, request context, graceful shutdown, and tests with supertest. - [Fastify](https://masyaka.github.io/injecute/frameworks/fastify.md): Use injecute with Fastify — Fastify plugins for HTTP, the container for services, typed without declaration merging, route plugins contributed by modules, request context, graceful shutdown, and tests with inject(). - [Hono](https://masyaka.github.io/injecute/frameworks/hono.md): Use injecute with Hono on Node.js, Bun, Deno and Cloudflare Workers — services built once and typed from the registrations, routes contributed by modules, request context, graceful shutdown, and tests with app.request(). - [Next.js](https://masyaka.github.io/injecute/frameworks/nextjs.md): Use injecute with the Next.js App Router — connections that survive hot reloads, typed services in server components, route handlers and server actions, graceful shutdown, request context, and tests without Next.js. - [GraphQL](https://masyaka.github.io/injecute/frameworks/graphql.md): Use injecute with GraphQL Yoga or Apollo Server — a DataLoader per request without a container per request, resolvers that close over typed services, a schema assembled from modules, and tests without a server. - [React, Vue and Solid](https://masyaka.github.io/injecute/frameworks/ui-frameworks.md): When a React, Vue or Solid app needs a container and when imports are enough — one core per widget, request or test, a client-side service graph, components that resolve services through the framework's context, TanStack Query, state management libraries, and what the container leaves to the framework. - [Coming from NestJS](https://masyaka.github.io/injecute/frameworks/nestjs.md): How NestJS's dependency injection maps to injecute — plain classes without legacy decorators or reflect-metadata, wiring checked at compile time, one simple pipeline — and how to move step by step. ### Concepts - [Design principles](https://masyaka.github.io/injecute/concepts/principles.md): The principles injecute is built on, what they mean for your code, their known exceptions, and the design tests a new feature has to pass. - [Roles: provider, registry, container](https://masyaka.github.io/injecute/concepts/roles.md): Why injecute gives consumers a ServiceProvider, modules a ServiceRegistry, and only the composition root the DIContainer. - [How resolution works](https://masyaka.github.io/injecute/concepts/resolution.md): Lookup through parent containers, which container runs a factory and owns the instance, decoration, middlewares, cycles and errors. - [Comparison](https://masyaka.github.io/injecute/concepts/comparison.md): How injecute compares with typed-inject, needle-di, Awilix, InversifyJS, tsyringe, NestJS and Effect, with the sources for every claim. ### Reference - [Errors](https://masyaka.github.io/injecute/errors.md): Every error injecute throws, with how to fix it. - [Migrating from 0.x to 1.0](https://masyaka.github.io/injecute/migration/0.x-to-1.0.md): Every breaking change between injecute 0.x and 1.0, with before/after examples. - [Changelog](https://masyaka.github.io/injecute/changelog.md) - [Versioning and support](https://masyaka.github.io/injecute/guide/versioning.md): What counts as a breaking change, which TypeScript versions and runtimes are supported, and how releases are published. ### Other - [INJECUTE_ALREADY_REGISTERED](https://masyaka.github.io/injecute/errors/already-registered.md): The key is already registered in this container or a parent - [INJECUTE_CIRCULAR_DEPENDENCY](https://masyaka.github.io/injecute/errors/circular-dependency.md): Services depend on each other in a cycle - [INJECUTE_CLASS_NOT_CONSTRUCTED](https://masyaka.github.io/injecute/errors/class-not-constructed.md): A class was called without new - [INJECUTE_DISPOSE_FAILED](https://masyaka.github.io/injecute/errors/dispose-failed.md): Some services failed to dispose - [INJECUTE_DISPOSED](https://masyaka.github.io/injecute/errors/disposed.md): The container is disposed - [INJECUTE_EXTENSION_RESULT](https://masyaka.github.io/injecute/errors/extension-result.md): An extension returned a container that is not this one or its child - [INJECUTE_INVALID_DEPENDENCY](https://masyaka.github.io/injecute/errors/invalid-dependency.md): A dependency is not a key, optional(key), collect(tag) or a function - [INJECUTE_INVALID_FACTORY](https://masyaka.github.io/injecute/errors/invalid-factory.md): The factory is not a function or class - [INJECUTE_INVALID_HOOK](https://masyaka.github.io/injecute/errors/invalid-hook.md): A lifecycle hook is not registered correctly - [INJECUTE_INVALID_OPTION](https://masyaka.github.io/injecute/errors/invalid-option.md): An option is not supported here - [INJECUTE_LIFECYCLE_STOPPED](https://masyaka.github.io/injecute/errors/lifecycle-stopped.md): The lifecycle of this container was stopped - [INJECUTE_NAMESPACE_CONFLICT](https://masyaka.github.io/injecute/errors/namespace-conflict.md): The namespace name is already used by a service - [INJECUTE_NAMESPACE_RESULT](https://masyaka.github.io/injecute/errors/namespace-result.md): A namespace callback returned something other than a new container - [INJECUTE_NO_PREVIOUS_DEFINITION](https://masyaka.github.io/injecute/errors/no-previous-definition.md): A service depends on itself but there is nothing to decorate - [INJECUTE_NOT_A_FUNCTION](https://masyaka.github.io/injecute/errors/not-a-function.md): call() was used on a service that is not a function - [INJECUTE_NOT_REGISTERED](https://masyaka.github.io/injecute/errors/not-registered.md): No service is registered under this key - [INJECUTE_NOTHING_TO_REPLACE](https://masyaka.github.io/injecute/errors/nothing-to-replace.md): A registration replaces a key that nothing is registered under - [INJECUTE_READ_ONLY](https://masyaka.github.io/injecute/errors/read-only.md): The object is read-only - [INJECUTE_RESOLUTION_FAILED](https://masyaka.github.io/injecute/errors/resolution-failed.md): A factory threw (or its promise rejected) while creating a service - [INJECUTE_SEALED](https://masyaka.github.io/injecute/errors/sealed.md): The container is sealed - [INJECUTE_UNDO_FAILED](https://masyaka.github.io/injecute/errors/undo-failed.md): A lifecycle hook could not be undone - [INJECUTE_UNKNOWN_EVENT](https://masyaka.github.io/injecute/errors/unknown-event.md): Unknown event name - [INJECUTE_WIRING_FAILED](https://masyaka.github.io/injecute/errors/wiring-failed.md): The wiring check found services that are missing or fail - [Playground](https://masyaka.github.io/injecute/playground.md): Edit a container in the browser and see its services graph.