Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••••••••••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

I've been doing Dependency Injection in Node.js without decorators for 9 years. Here's why I still think it's the right call.

Ok so first, let me be honest. This post is partly me venting. I've been maintaining node-dependency-injection for about 9 years now. 300 stars on GitHub. Not exactly viral. And every time I look at InversifyJS or tsyringe climbing in…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Ok so first, let me be honest. This post is partly me venting.



I've been maintaining node-dependency-injection for about 9 years now. 300 stars on GitHub. Not exactly viral. And every time I look at InversifyJS or tsyringe climbing in popularity I think "yeah, but at what cost".



So let me explain my problem with decorators.









The coupling nobody talks about



When you write this:




@Injectable()
export class UserService {
constructor(@Inject(MAILER_TOKEN) private mailer: IMailer) {}
}






Where does that @Injectable() live? In your DI framework. Which means your UserService — which is domain logic, business rules, the thing that should outlive any framework decision — now has a direct dependency on your IoC container library.



Your domain knows about your infrastructure. That's the wrong direction.



I know, I know. "It's just a decorator, it doesn't do anything". But it's still an import. It's still coupling. And if you ever want to swap the container, or move that service somewhere else, or just test it without spinning up the whole container — you now have to think about it.



With NDI, your service is just a class:




export class UserService {
constructor(private mailer: IMailer) {}
}






That's it. No imports from my library. No decorators. No metadata. The service doesn't know it's being injected. The wiring lives completely outside — in a YAML file or in a bootstrap file. Your domain stays clean.









"But Symfony does decorators and it's fine"



Symfony doesn't use decorators in services actually. The DI config is external — YAML, XML, PHP config files. Your service is just a PHP class. That's literally what inspired NDI from the beginning.









What NDI actually does



Quick example. You have two payment providers and you want to inject the right one based on context:




services:
payment.stripe:
class: 'payments/StripePayment'
keyed:
group: payment
key: stripe
default: true

payment.paypal:
class: 'payments/PaypalPayment'
keyed:
group: payment
key: paypal

checkout.service:
class: 'CheckoutService'
arguments: ['@keyed(payment, stripe)']









// CheckoutService.ts — pure class, zero framework imports
export class CheckoutService {
constructor(private payment: IPaymentService) {}

async process(order: Order) {
return this.payment.charge(order.total)
}
}






The strategy pattern, completely outside the class. You can swap stripe for paypal by changing one line of config. Your CheckoutService literally doesn't care.









Autowire without decorators



This is the thing I'm most proud of honestly. NDI can read your TypeScript constructor types and wire everything automatically — without a single decorator:




// Just normal TypeScript. No imports from NDI.
export default class OrderService {
constructor(
private readonly repo: OrderRepository,
private readonly mailer: MailService
) {}
}









const container = new ContainerBuilder(false, '/src')
const autowire = new Autowire(container)
await autowire.process()
await container.compile()

const orders = container.get(OrderService) // fully wired






It parses the TypeScript AST, finds the constructor params, resolves them by type. No reflect-metadata, no decorators, no nothing. Just types.









Conditional services



One feature I don't see in other containers — register services based on environment:




services:
cache.redis:
class: 'services/RedisCache'
when:
env_exists: REDIS_URL

cache.memory:
class: 'services/InMemoryCache'
when:
missing: cache.redis






In prod you have Redis, the memory cache never gets instantiated. Locally you don't, it falls back. Zero code changes.









Compiler passes



Borrowed from Symfony again. You can transform the container at build time before it compiles:




class AddLoggingPass implements CompilerPass {
async process(container: ContainerBuilder) {
for (const { id, definition } of container.findTaggedServiceIds('loggable')) {
// wrap every tagged service with a logging decorator
definition.setDecorator('logger.decorator')
}
}
}

container.addCompilerPass(new AddLoggingPass())






Try doing that cleanly with @Injectable decorators.









Why 300 stars after 9 years



Honestly? Because the ecosystem trained everyone to associate "TypeScript DI" with decorators. NestJS made it the default. And NestJS is great for many things — if you're all-in on the framework, the DI just comes along.



But if you care about Clean Architecture, hexagonal, keeping domain logic free from infrastructure concerns — decorators in your services is exactly what you're trying to avoid.



NDI is for people who want the DI container to be infrastructure, not something that bleeds into your domain. The wiring should be boring config, not annotations on your business logic.



I've been using this in production for 9 years. Works fine. And my UserService still doesn't know what a container is.






1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Vulnerability Remediation & Verification
1 Warnungen
title: Detect Exploitation - I've been doing Dependency Injection in Node.js without decorators for 9 years. Here's why I still think it's the right call.
id: cef5989a-15c5-4341-b0fa-15e8a2c2a49f
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-25
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-25"
        description = "YARA Signature for "
    strings:
        $str = "I\'ve been doing Dependency Inj" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("Ive been doing Dependency Injection in N")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*Ive been doing Dependency Injection in N*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "Ive been doing Dependency Injection in N"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich I've been doing Dependency Injection in .... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten I've been doing Dependency Injection in Node.js without decorators for 9 years. Here's why I still think it's the right call.

Thematisch verwandte Begriffe: been, doing, Dependency, Injection · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-87722 | Uncontrolled Resource Consumption (CWE-400 / CWE-1333) in regex search q…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...
↗ Original-Quelle