Version v3.0.0 Size 2.4 KB gzip Dependencies Zero dependencies
Why Conduit?
Conduit makes service wiring explicit. Typed builders create immutable providers, static graphs are validated at construction, and dependency tuples drive creation and disposal. Resolve one root token or a typed composition map.
ts
// Before
const service = createService(createApi(config), logger);
// After
const container = createContainer([
valueProvider(Config, config),
factoryProvider(Api, [Config], (config) => createApi(config)),
factoryProvider(Service, [Api, Logger], (api, logger) => createService(api, logger)),
]);
const services = await container.resolve({ service: Service });| Feature | Conduit | Inversify | tsyringe |
|---|---|---|---|
| Dependencies | Explicit token tuples | Decorators/runtime metadata | Decorators/runtime metadata |
| Async factories | Partial | Partial | |
| Lifecycle scopes | |||
| Runtime dependencies | 0 |
Use Conduit when application services need explicit wiring and owned lifecycle cleanup.
Consider direct imports when dependencies are static, small, and need no replacement or disposal boundary.
Installation
sh
pnpm add @vielzeug/conduitsh
npm install @vielzeug/conduitsh
yarn add @vielzeug/conduitQuick Start
ts
import { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit';
const Config = token<{ baseUrl: string }>('Config');
const Client = token<{ url: string }>('Client');
const container = createContainer([
valueProvider(Config, { baseUrl: '/api' }),
factoryProvider(Client, [Config], (config) => ({ url: `${config.baseUrl}/users` })),
]);
const services = await container.resolve({ client: Client });
console.log(services.client);
await container.dispose();Features
token: typed dependency identityvalueProvider/factoryProvider: token-safe immutable registrationscreateContainer: validated provider graphresolve: direct service or typed composition mapscope: explicit request and job ownershipdispose: in-flight-safe resource cleanup