{"id":12737,"library":"inversify","title":"InversifyJS IoC Container","description":"InversifyJS is a robust and lightweight Inversion of Control (IoC) container for JavaScript and TypeScript applications, currently at version 8.1.0. It facilitates Dependency Injection (DI) by using decorators and TypeScript's reflection capabilities to manage the instantiation and injection of dependencies, promoting adherence to SOLID principles, good OOP, and IoC practices. The library is actively maintained with frequent minor and patch releases across its core and ecosystem packages, addressing new features and bug fixes. Key differentiators include its strong TypeScript integration, minimal runtime overhead, and a developer-friendly API designed to enhance modularity, testability, and maintainability. InversifyJS emphasizes a explicit dependency graph, helping developers build scalable applications by reducing coupling between components. It relies heavily on `reflect-metadata` for design-time type information, which is a fundamental aspect of its operation.","status":"active","version":"8.1.0","language":"javascript","source_language":"en","source_url":"https://github.com/inversify/monorepo","tags":["javascript","dependency injection","dependency inversion","di","inversion of control container","ioc","node","typescript"],"install":[{"cmd":"npm install inversify","lang":"bash","label":"npm"},{"cmd":"yarn add inversify","lang":"bash","label":"yarn"},{"cmd":"pnpm add inversify","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for runtime type introspection via TypeScript decorators; must be imported once at application entry point for the global `Reflect` object to be available.","package":"reflect-metadata","optional":false}],"imports":[{"note":"InversifyJS v8 is an ESM-only package. While Node.js 20.19.0+ supports `require()` for ESM, direct `import` statements are the idiomatic way. For older Node.js versions (e.g., 18 or earlier), consider upgrading or using dynamic `import()`.","wrong":"const { Container } = require('inversify');","symbol":"Container","correct":"import { Container } from 'inversify';"},{"note":"Decorator for marking classes as eligible for dependency injection. Always lowercase `injectable`.","wrong":"import { Injectable } from 'inversify';","symbol":"@injectable","correct":"import { injectable } from 'inversify';"},{"note":"Decorator for injecting dependencies into constructor parameters or properties. Always lowercase `inject`.","wrong":"import { Inject } from 'inversify';","symbol":"@inject","correct":"import { inject } from 'inversify';"},{"note":"While `inversify` itself doesn't export `TYPES`, it's a common pattern to define binding identifiers (Symbols, strings, or classes) in a separate file, typically named `types.ts` or `constants.ts`, and import them for use with `container.bind()`.","symbol":"TYPES","correct":"import { TYPES } from './types';"},{"note":"This import must occur *once* at the very top of your application's entry file to ensure the global `Reflect` object is available before any InversifyJS decorators are processed. Failure to do so will result in runtime errors.","symbol":"reflect-metadata polyfill","correct":"import 'reflect-metadata';"}],"quickstart":{"code":"import 'reflect-metadata';\nimport { Container, injectable, inject } from 'inversify';\n\n// 1. Define interfaces (abstractions)\ninterface Warrior {\n  fight(): string;\n  sneak(): string;\n}\n\ninterface Weapon {\n  hit(): string;\n}\n\ninterface ThrowableWeapon {\n  throw(): string;\n}\n\n// 2. Define binding identifiers (symbols or classes)\nconst TYPES = {\n  Warrior: Symbol.for('Warrior'),\n  Weapon: Symbol.for('Weapon'),\n  ThrowableWeapon: Symbol.for('ThrowableWeapon'),\n};\n\n// 3. Implement concrete classes and use decorators\n@injectable()\nclass Katana implements Weapon {\n  public hit(): string {\n    return 'cut!';\n  }\n}\n\n@injectable()\nclass Shuriken implements ThrowableWeapon {\n  public throw(): string {\n    return 'hit!';\n  }\n}\n\n@injectable()\nclass Ninja implements Warrior {\n  private _katana: Weapon;\n  private _shuriken: ThrowableWeapon;\n\n  public constructor(\n    @inject(TYPES.Weapon) katana: Weapon,\n    @inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon,\n  ) {\n    this._katana = katana;\n    this._shuriken = shuriken;\n  }\n\n  public fight(): string {\n    return this._katana.hit();\n  }\n\n  public sneak(): string {\n    return this._shuriken.throw();\n  }\n}\n\n// 4. Create and configure a container\nconst myContainer = new Container();\nmyContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);\nmyContainer.bind<Weapon>(TYPES.Weapon).to(Katana);\nmyContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(Shuriken);\n\n// 5. Resolve dependencies\nconst ninja = myContainer.get<Warrior>(TYPES.Warrior);\n\nconsole.log(ninja.fight()); // Expected output: cut!\nconsole.log(ninja.sneak()); // Expected output: hit!\n","lang":"typescript","description":"This quickstart demonstrates the core concepts of InversifyJS: defining interfaces, using symbols for binding identifiers, marking classes with `@injectable`, injecting dependencies with `@inject`, configuring the `Container` with `bind().to()`, and finally resolving an instance using `container.get()`. It highlights the necessary `reflect-metadata` import."},"warnings":[{"fix":"Review all container API calls. Replace `await container.load(module)` with `container.loadAsync(module)` if asynchronous behavior is needed, or simply `container.load(module)` if synchronous is desired (which is now the default). Apply similar changes for `unbind`, `rebind`, `unload`, and `unbindAll`.","message":"InversifyJS v8 introduced a 'sync-first' naming convention. Methods like `container.load`, `unbind`, `rebind`, and `unload` are now synchronous by default. Their asynchronous counterparts are suffixed with `Async` (e.g., `container.loadAsync`). This reverses the behavior introduced in v7, where these methods were asynchronous by default.","severity":"breaking","affected_versions":">=8.0.0"},{"fix":"Upgrade to Node.js 20.19.0+ or 22+. If sticking with older Node.js, replace `require('inversify')` with `import('inversify')` for async loading or transition your project to native ESM.","message":"InversifyJS v8 is an ESM-only package and no longer provides a CommonJS build. While Node.js 20.19.0 and later (or Node.js 22+) support `require()` for ESM packages, older Node.js versions (e.g., 18 or earlier, which reached EOL in April 2025) will require projects to either upgrade Node.js or switch to dynamic `import('inversify')` where acceptable.","severity":"breaking","affected_versions":">=8.0.0"},{"fix":"For classes with `protected` or `private` constructors used as identifiers, switch to `Symbol.for()` or a custom symbol as the service identifier. For typical class-based identifiers, no change is needed.","message":"The `ServiceIdentifier<T>` type in v8 no longer accepts an arbitrary `Function` but strictly requires `Newable` or `AbstractNewable`. This primarily impacts using classes with `protected` or `private` constructors as service identifiers, where a `Symbol` identifier should now be used instead.","severity":"breaking","affected_versions":">=8.0.0"},{"fix":"Migrate any `toProvider` bindings to `toFactory` bindings, utilizing the `Factory` type.","message":"The `toProvider` binding method and the `Provider` type have been completely removed in InversifyJS v8. The `Factory` pattern (introduced in v7) covers all previous use cases of `Provider` with greater flexibility and a cleaner API.","severity":"breaking","affected_versions":">=8.0.0"},{"fix":"Ensure `reflect-metadata` is installed and the `import 'reflect-metadata';` statement is the first line in your main application file. Also, configure `tsconfig.json` with `\"experimentalDecorators\": true`, `\"emitDecoratorMetadata\": true`, and `\"target\": \"ES2022\"` or later.","message":"InversifyJS critically depends on `reflect-metadata` for its decorator-based dependency injection. It must be installed (`npm install reflect-metadata`) and imported once at the very top of your application's entry file: `import 'reflect-metadata';`. Failure to do so will result in runtime errors like 'Reflect is not defined' or 'TypeError: Reflect.hasOwnMetadata is not a function'.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"For injection inheritance, use the `@injectFromBase` decorator. If you relied on custom metadata or middlewares, you may need to reconsider your approach or implement similar functionality manually.","message":"InversifyJS v7 deprecated implicit injection inheritance in favor of the `@injectFromBase` decorator. In v8, custom metadata and middlewares were removed entirely with no direct replacement, contributing to library simplification.","severity":"breaking","affected_versions":">=7.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Add `import 'reflect-metadata';` as the very first line of your application's entry file. Ensure `reflect-metadata` is installed as a dependency. Check `tsconfig.json` for `\"emitDecoratorMetadata\": true` and `\"experimentalDecorators\": true`.","cause":"The `reflect-metadata` polyfill was not imported or was imported too late.","error":"TypeError: Reflect.hasOwnMetadata is not a function"},{"fix":"Ensure `container.bind<T>(TYPES.MyService).to(MyServiceImpl);` is called before attempting to `container.get<T>(TYPES.MyService);`. Double-check the `ServiceIdentifier` used in `bind` and `get` matches exactly.","cause":"A dependency was requested from the container but no `container.bind()` call exists for that `ServiceIdentifier` (e.g., `Symbol`, string, or class).","error":"No matching bindings found for serviceIdentifier: Symbol(MyService)"},{"fix":"Identify the circular dependency. Strategies to resolve include: refactoring to break the cycle, using an initializer method (`@postConstruct`), using `toDynamicValue` or `toFactory` for lazy loading, or introducing an intermediate interface/abstraction.","cause":"This typically indicates a circular dependency between services where Service A depends on Service B, and Service B directly or indirectly depends back on Service A, causing an infinite loop during instantiation.","error":"Maximum call stack size exceeded"},{"fix":"Add `import { Container } from 'inversify';` to the top of your file. If using CommonJS in an environment that doesn't support `require(esm)` (e.g., Node.js < 20.19.0), you might need to use dynamic imports or transpile your code to a compatible module format.","cause":"The `Container` class was used without being imported or without its module being properly transpiled/resolved.","error":"ReferenceError: Container is not defined"}],"ecosystem":"npm"}