Announcing InversifyJS 8.1.3
We're happy to announce InversifyJS 8.1.3, a release focused on performance optimizations in the container resolution path.
Dependency injection is rarely the bottleneck in a well-designed application, so we do not want to oversell microbenchmark wins as a universal upgrade story. That said, if your codebase relies on complex transient services or resolves large object graphs repeatedly, this release can reduce overhead in the places where container work is actually visible.
The benchmarks below were taken from packages/container/tools/container-benchmarks/src/bin/run.ts and compare the current implementation against previous InversifyJS releases.
[CJS] Running benchmarks...
Get service in singleton scope
┌─────────┬────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'inversifyCurrent' │ '256.36 ± 0.17%' │ '240.00 ± 10.00' │ '4085114 ± 0.01%' │ '4166667 ± 166667' │ 3900747 │
│ 1 │ 'inversify6' │ '1115.0 ± 0.27%' │ '1022.0 ± 30.00' │ '945343 ± 0.03%' │ '978474 ± 27903' │ 896894 │
│ 2 │ 'inversify7' │ '314.98 ± 0.14%' │ '291.00 ± 9.00' │ '3296324 ± 0.01%' │ '3436426 ± 103093' │ 3174774 │
│ 3 │ 'inversify8' │ '276.02 ± 0.13%' │ '260.00 ± 10.00' │ '3766103 ± 0.01%' │ '3846154 ± 142450' │ 3622979 │
│ 4 │ 'awilix' │ '233.92 ± 0.34%' │ '211.00 ± 9.00' │ '4561593 ± 0.01%' │ '4739337 ± 193882' │ 4274933 │
│ 5 │ 'NestJS' │ '327.08 ± 0.36%' │ '301.00 ± 9.00' │ '3211162 ± 0.01%' │ '3322259 ± 96453' │ 3057333 │
│ 6 │ 'tsyringe' │ '309.53 ± 0.31%' │ '290.00 ± 10.00' │ '3385338 ± 0.01%' │ '3448276 ± 123153' │ 3230725 │
└─────────┴────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
inversifyCurrent vs inversify6 Speedup: 4.321x
inversifyCurrent vs inversify7 Speedup: 1.239x
inversifyCurrent vs inversify8 Speedup: 1.085x
inversifyCurrent vs awilix Speedup: 0.896x
inversifyCurrent vs NestJS Speedup: 1.272x
inversifyCurrent vs tsyringe Speedup: 1.207x
Get service in transient scope
┌─────────┬────────────────────┬──────────────────┬───────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼────────────────────┼──────────────────┼───────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'inversifyCurrent' │ '281.41 ± 0.25%' │ '261.00 ± 10.00' │ '3702193 ± 0.01%' │ '3831418 ± 141381' │ 3553538 │
│ 1 │ 'inversify6' │ '5750.8 ± 0.28%' │ '5350.0 ± 80.00' │ '180996 ± 0.05%' │ '186916 ± 2754' │ 173890 │
│ 2 │ 'inversify7' │ '609.69 ± 0.15%' │ '581.00 ± 10.00' │ '1690669 ± 0.01%' │ '1721170 ± 30143' │ 1640183 │
│ 3 │ 'inversify8' │ '445.85 ± 0.28%' │ '401.00 ± 10.00' │ '2386816 ± 0.02%' │ '2493766 ± 60676' │ 2242894 │
│ 4 │ 'awilix' │ '449.01 ± 0.38%' │ '421.00 ± 10.00' │ '2323630 ± 0.01%' │ '2375297 ± 55111' │ 2227134 │
│ 5 │ 'NestJS' │ '11058 ± 1.98%' │ '9397.0 ± 290.00' │ '100822 ± 0.10%' │ '106417 ± 3377' │ 90431 │
│ 6 │ 'tsyringe' │ '468.15 ± 0.16%' │ '441.00 ± 10.00' │ '2213899 ± 0.01%' │ '2267574 ± 52612' │ 2136062 │
└─────────┴────────────────────┴──────────────────┴───────────────────┴────────────────────────┴────────────────────────┴─────────┘
inversifyCurrent vs inversify6 Speedup: 20.455x
inversifyCurrent vs inversify7 Speedup: 2.190x
inversifyCurrent vs inversify8 Speedup: 1.551x
inversifyCurrent vs awilix Speedup: 1.593x
inversifyCurrent vs NestJS Speedup: 36.720x
inversifyCurrent vs tsyringe Speedup: 1.672x
Get complex service in singleton scope
┌─────────┬────────────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼────────────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'inversifyCurrent' │ '264.21 ± 0.25%' │ '250.00 ± 9.00' │ '3931347 ± 0.01%' │ '4000000 ± 149378' │ 3784803 │
│ 1 │ 'inversify6' │ '1120.0 ± 1.66%' │ '1022.0 ± 30.00' │ '943130 ± 0.02%' │ '978474 ± 28806' │ 892870 │
│ 2 │ 'inversify7' │ '315.64 ± 0.37%' │ '291.00 ± 10.00' │ '3331150 ± 0.01%' │ '3436426 ± 114167' │ 3168127 │
│ 3 │ 'inversify8' │ '286.70 ± 0.36%' │ '261.00 ± 9.00' │ '3668124 ± 0.01%' │ '3831418 ± 127714' │ 3487997 │
│ 4 │ 'awilix' │ '258.01 ± 0.26%' │ '241.00 ± 10.00' │ '4047521 ± 0.01%' │ '4149378 ± 165314' │ 3875780 │
│ 5 │ 'NestJS' │ '335.19 ± 0.15%' │ '311.00 ± 10.00' │ '3088769 ± 0.01%' │ '3215434 ± 100169' │ 2983398 │
│ 6 │ 'tsyringe' │ '319.12 ± 0.31%' │ '300.00 ± 10.00' │ '3274949 ± 0.01%' │ '3333333 ± 107527' │ 3133607 │
└─────────┴────────────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
inversifyCurrent vs inversify6 Speedup: 4.168x
inversifyCurrent vs inversify7 Speedup: 1.180x
inversifyCurrent vs inversify8 Speedup: 1.072x
inversifyCurrent vs awilix Speedup: 0.971x
inversifyCurrent vs NestJS Speedup: 1.273x
inversifyCurrent vs tsyringe Speedup: 1.200x
Get complex service in transient scope
┌─────────┬─────────────────────────────────────┬───────────────────┬───────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼─────────────────────────────────────┼───────────────────┼───────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'inversifyCurrent' │ '72890 ± 0.67%' │ '68157 ± 2084.0' │ '14239 ± 0.20%' │ '14672 ± 452' │ 13720 │
│ 1 │ 'inversifyCurrent (Resolved Value)' │ '76522 ± 0.46%' │ '74499 ± 1523.0' │ '13289 ± 0.13%' │ '13423 ± 274' │ 13069 │
│ 2 │ 'inversify6' │ '5389772 ± 2.50%' │ '5120533 ± 57307' │ '189 ± 1.44%' │ '195 ± 2' │ 186 │
│ 3 │ 'inversify7' │ '317547 ± 0.74%' │ '306793 ± 2199.5' │ '3198 ± 0.28%' │ '3260 ± 23' │ 3150 │
│ 4 │ 'inversify8' │ '181530 ± 0.62%' │ '176230 ± 751.00' │ '5575 ± 0.17%' │ '5674 ± 24' │ 5509 │
│ 5 │ 'awilix' │ '280252 ± 0.34%' │ '274372 ± 2154.0' │ '3588 ± 0.18%' │ '3645 ± 29' │ 3569 │
│ 6 │ 'NestJS' │ '81098 ± 1.65%' │ '72105 ± 1392.0' │ '13213 ± 0.24%' │ '13869 ± 269' │ 12331 │
│ 7 │ 'tsyringe' │ '226590 ± 0.43%' │ '220552 ± 2736.0' │ '4454 ± 0.20%' │ '4534 ± 57' │ 4414 │
└─────────┴─────────────────────────────────────┴───────────────────┴───────────────────┴────────────────────────┴────────────────────────┴─────────┘
inversifyCurrent vs inversifyCurrent (Resolved Value) Speedup: 1.071x
inversifyCurrent vs inversify6 Speedup: 75.489x
inversifyCurrent vs inversify7 Speedup: 4.452x
inversifyCurrent vs inversify8 Speedup: 2.554x
inversifyCurrent vs awilix Speedup: 3.969x
inversifyCurrent vs NestJS Speedup: 1.078x
inversifyCurrent vs tsyringe Speedup: 3.197x
Get complex async service in transient scope
┌─────────┬────────────────────┬───────────────────┬───────────────────┬────────────────────────┬────────────────────────┬─────────┐
│ (index) │ Task name │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├─────────┼────────────────────┼───────────────────┼───────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ 'inversifyCurrent' │ '368917 ± 0.83%' │ '353280 ± 7113.0' │ '2767 ± 0.38%' │ '2831 ± 57' │ 2711 │
│ 1 │ 'inversify6' │ '5036349 ± 2.42%' │ '4741104 ± 94917' │ '202 ± 1.50%' │ '211 ± 4' │ 199 │
│ 2 │ 'inversify7' │ '720247 ± 0.83%' │ '699286 ± 5881.0' │ '1405 ± 0.42%' │ '1430 ± 12' │ 1389 │
│ 3 │ 'inversify8' │ '592877 ± 0.98%' │ '569894 ± 7464.0' │ '1718 ± 0.47%' │ '1755 ± 23' │ 1687 │
└─────────┴────────────────────┴───────────────────┴───────────────────┴────────────────────────┴────────────────────────┴─────────┘
inversifyCurrent vs inversify6 Speedup: 13.689x
inversifyCurrent vs inversify7 Speedup: 1.969x
inversifyCurrent vs inversify8 Speedup: 1.610x
What improved
The strongest improvements show up when resolving transient services:
- Get service in transient scope:
281.41 nsaverage latency, about 1.58x faster than InversifyJS 8.0 - Get complex service in transient scope:
72,890 nsaverage latency, about 2.49x faster than InversifyJS 8.0 - Get complex async service in transient scope:
368,917 nsaverage latency, about 1.61x faster than InversifyJS 8.0
Singleton resolution also improved modestly:
- Get service in singleton scope:
256.36 nsaverage latency, about 1.08x faster than InversifyJS 8.0 - Get complex service in singleton scope:
264.21 nsaverage latency, about 1.09x faster than InversifyJS 8.0
For reference, the current implementation also remains significantly faster than InversifyJS 6 and 7 in the scenarios we benchmarked, especially in transient-heavy workloads.
What this means for you
If your application mostly resolves a few long-lived services, you may not notice a dramatic end-to-end change. If, however, you build plugin systems, request-scoped graphs, or other transient-heavy designs, this release should shave off some container overhead without requiring any code changes.
As always, benchmark data should be read in context. Measure your own application if you want to understand where the real bottlenecks are, but if container resolution is part of that profile, 8.1.3 should be a worthwhile upgrade.
Thanks for trying out InversifyJS 8.1.3, and please let us know if you run into any issues.
