This page is also available in Italiano.

Continua in italiano

Comparison

Most DI containers in the TypeScript ecosystem lean on reflect-metadata and decorators for automatic dependency discovery. TinyDI takes the opposite stance — here is exactly how that trade-off compares.

TinyDI vs. TSyringe

TinyDITSyringe
Dependency discoveryExplicit, via factoriesAutomatic, via decorators + reflect-metadata
Decorators requiredNoYes (@injectable, @inject, ...)
Compiler flags requiredNoneexperimentalDecorators, emitDecoratorMetadata
Runtime dependenciesNonereflect-metadata
Token identitysymbol-backed Token<T>String tokens or classes
LifetimesSingleton, TransientSingleton, Transient, ResolutionScoped, ContainerScoped

TSyringe is a great choice if you want automatic constructor injection and don't mind decorators and reflect-metadata in your project. TinyDI trades that convenience for explicitness and a smaller surface area.

TinyDI vs. InversifyJS

TinyDIInversifyJS
Dependency discoveryExplicit, via factoriesAutomatic, via decorators + reflect-metadata
Decorators requiredNoYes (@injectable, @inject, ...)
Compiler flags requiredNoneexperimentalDecorators, emitDecoratorMetadata
Runtime dependenciesNonereflect-metadata
Concepts to learnToken, Container, ServiceLifetimeContainers, modules, bindings, scopes, middleware
LifetimesSingleton, TransientSingleton, Transient, Request, custom scopes

InversifyJS offers a much larger feature set (modules, middleware, multi-injection, tagging) at the cost of a larger API surface and a runtime dependency on reflection. TinyDI intentionally covers a much smaller, simpler slice of that problem space.

TinyDI vs. a hand-rolled composition root

Many experienced developers skip a DI container entirely: one file wires every dependency by hand with plain function calls. That composition root, not another container, is what TinyDI actually competes with most often.

TinyDIHand-rolled composition root
Dependency discoveryExplicit, via factoriesExplicit, via plain function calls
Circular dependency detectionAutomatic — throws CircularDependencyError with the full cycleManual — a cycle either throws an unrelated runtime error or silently resolves to undefined, depending on module load order
Lifetime managementBuilt in: Singleton or Transient, chosen per registrationHand-written: singletons are typically module-level constants, transients need a manual factory function
Swapping implementations in testsremove() + registerInstance() on any tokenUsually requires editing the composition root itself, or a manual parameter-passing seam
Runtime costOne Map lookup per resolve() callNone — direct function calls
Concepts to learnToken, Container, ServiceLifetimeNone — it's the language you already know

A hand-rolled composition root is a perfectly valid choice for a small project with few services. TinyDI mainly earns its keep once circular-dependency debugging, consistent lifetime management, or swapping fakes in tests start costing real time to do by hand.

to navigate to select Esc to close