A modern, lightweight dependency injection container for TypeScript with native decorators, inspired by industry-leading frameworks.
The DI library that doesn't make you want to inject yourself with coffee ☕
NexusDI is a modern, lightweight dependency injection (DI) container for TypeScript and Node.js. It uses native decorators and a modular architecture to help you write scalable, testable, and maintainable applications. Inspired by frameworks like InversifyJS, tsyringe, TypeDI, and NestJS, NexusDI brings high performance and a developer-friendly API to your JavaScript and TypeScript projects. Works seamlessly in Node.js and modern JavaScript environments.
We want your input!
NexusDI thrives on community input!
We have a number of open RFCs and discussions, and your feedback can help guide the direction of the project.
Jump in and let us know what you think!
👉 Share your ideas and feedback in the Ideas Discussions
We look forward to hearing from you!
- 🚀 TypeScript-Native Decorators – Harness the power of modern TypeScript decorators for robust, type-safe dependency injection
- 🧩 Powerful Module System - Organize your application into modules with support for both static and dynamic configuration
- ⚡ Dynamic Configuration - Static methods for environment-specific module configuration (inspired by industry leaders)
- 🎯 Developer-Friendly API - Clean and intuitive API that makes dependency management simple
- 📦 Lightweight - Low dependency, minimal bundle size
- 🔧 Flexible - Support for both class-based and factory providers
- TypeScript-first: Designed for modern TypeScript and JavaScript projects.
- Zero bloat: Minimal dependencies, small bundle size, and no runtime polyfills required.
- Native decorators: Uses the latest TypeScript decorator syntax for clean, intuitive code.
- Modular & extensible: Organize your app with modules, plugins, and dynamic configuration.
- Testable: Easily mock or override providers for unit and integration testing.
- Inspired by the best: Familiar patterns for those coming from InversifyJS, tsyringe, TypeDI or NestJS.
NexusDI is an alternative to:
- InversifyJS
- tsyringe
- TypeDI
- NestJS DI system
Library | Startup Time | Resolution Time | Memory Usage | Bundle Size |
---|---|---|---|---|
NexusDI | 1.3μs | 0.2μs | 6KB | 96KB |
InversifyJS | 22.2μs | 1.4μs | 32KB | 114KB |
tsyringe | 45.2μs | 0.9μs | 150KB | 99KB |
TypeDI | 2.0μs | 0.1μs | 2KB | 89KB |
Based on real benchmarks: 1,000 startup iterations, 10,000 resolution iterations, Node.js v22.13.1, M1 Pro MacBook.
👉 See the full Performance & Bundle Size article for methodology and details.
npm install @nexusdi/core
tsconfig.json
{
"compilerOptions": {
"target": "ES2022", // or later
"experimentalDecorators": true,
"useDefineForClassFields": true
}
}
Note: Only these options are required for NexusDI v0.3+. You do not need to install or import
reflect-metadata
.
import { Nexus, Service, Token, Inject } from '@nexusdi/core';
// Define service interface and token
interface IUserService {
getUsers(): Promise<User[]>;
}
const USER_SERVICE = new Token<IUserService>('UserService');
// Create service with dependency injection
@Service(USER_SERVICE)
class UserService implements IUserService {
constructor(@Inject(LOGGER_SERVICE) private logger: ILoggerService) {}
async getUsers(): Promise<User[]> {
this.logger.info('Fetching users');
return [{ id: 1, name: 'John' }];
}
}
// Use the container
const container = new Nexus();
container.set(UserModule);
const userService = container.get(USER_SERVICE);
NexusDI supports dynamic module configuration with a simple base class approach:
import { Module, DynamicModule } from '@nexusdi/core';
interface DatabaseConfig {
host: string;
port: number;
database: string;
}
const DATABASE_CONFIG = Symbol('DATABASE_CONFIG');
@Module({
providers: [DatabaseService], // Simplified format - uses @Service decorator token
})
class DatabaseModule extends DynamicModule<DatabaseConfig> {
protected readonly configToken = DATABASE_CONFIG;
}
// Usage
const container = new Nexus();
// Synchronous configuration
container.set(
DatabaseModule.config({
host: 'localhost',
port: 5432,
database: 'dev_db',
})
);
// Asynchronous configuration
container.set(
DatabaseModule.configAsync(async () => ({
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
database: process.env.DB_NAME,
}))
);
We welcome contributions! Please see our Contributing Guide for details.
MIT License - see LICENSE for details.