7. Apr. 20255 min

Warum ich 2025 von Nest.js zu Fastify und DDD gewechselt bin

Ein persoenlicher Blick darauf, warum ich 2025 von Nest.js weggegangen bin und Fastify mit Domain Driven Design fuer schlankere, klarere Node.js-Backend-Architektur gewaehlt habe.

Als ich Nest.js zum ersten Mal entdeckte, wirkte es wie ein vielversprechender Weg, Ordnung und Enterprise-Patterns in die Node.js-Welt zu bringen. TypeScript, Decorators, Module und Dependency Injection sahen ueberzeugend aus, fast wie ein Java-inspiriertes Oekosystem fuer JavaScript.

Am Anfang war diese Struktur attraktiv. Sie gab Teams bekannte Konzepte, klare Orte fuer Controller und Services und ein Framework, das bereit fuer ernsthafte Backend-Systeme wirkte.

Nach mehreren Projekten damit wurde mir aber klar, dass die Komplexitaet oft groesser sein kann als der Nutzen. 2025 habe ich mich bewusst von Nest.js entfernt und begonnen, Fastify zusammen mit Domain Driven Design zu verwenden.

Das ist keine allgemeine Aussage, dass Nest.js schlecht ist. Es ist meine persoenliche Erfahrung mit den Tradeoffs und warum Fastify plus DDD am Ende besser zu meinem Workflow gepasst hat.

Wo Nest.js fuer mich zu kurz kam

Nest.js kann produktiv sein, besonders wenn ein Team seine Konventionen mag. Das Problem war fuer mich, dass das Framework in einem TypeScript-Backend oft mehr Zeremonie hinzufuegte, als ich wollte.

Zu viele Schichten und Abstraktionen

Nest.js uebernimmt viele Ideen aus Javas Spring Framework: Dependency-Injection-Container, Decorators, Module, Provider, Services, Guards, Interceptors und mehr.

Diese Konzepte koennen nuetzlich sein, aber in TypeScript und JavaScript lassen sich viele davon auch einfacher umsetzen. Manchmal reicht es, eine Funktion, ein Objekt oder eine Instanz direkt aus einem Modul zu exportieren.

Mit Nest.js hatte ich oft das Gefuehl, zuerst Code fuer das Framework und erst danach fuer die Anwendung zu schreiben. Die Struktur war konsistent, brachte aber mehrere Indirektionsschichten mit, bevor ein Request die Business-Logik erreichte.

Diese zusaetzliche "Magie" wurde besonders bei Wartung und Debugging sichtbar.

Debugging wurde langsamer als noetig

Beim Entwickeln von APIs sah ich Stack Traces, die auf tief gewrappte, kompilierte JavaScript-Dateien zeigten. Einen Fehler zur urspruenglichen TypeScript-Quelle zurueckzuverfolgen, konnte muehsam werden.

Das Problem war nicht, dass Debugging unmoeglich war. Das Problem war, dass es oft mehr Kontext brauchte, als es sollte. Decorators, Wrapper, generierte Metadaten und Framework-Lifecycle-Hooks verlaengerten den Weg vom Fehler zur Ursache.

Wenn ich schnell einen Fix brauchte oder ein Produktionsproblem verstehen wollte, war diese Reibung spuerbar.

Versionskonflikte und Dependency-Rauschen

Das Node.js-Oekosystem bewegt sich schnell. Ein kleines Library-Update kann die Kompatibilitaet mit einem anderen Package brechen, besonders wenn sich TypeScript-Definitionen verschieben.

Ich hatte Situationen, in denen Nest.js nach einer kleinen Versionsaenderung in einer sekundaeren Dependency nicht mehr gebaut hat. Manchmal war die Runtime-Logik in Ordnung, aber Types, Decorators oder framework-spezifische Packages passten nicht mehr zusammen.

Versionen zurueckzurollen oder Workarounds zu suchen, kostete Zeit und Energie, die ich lieber in Produktlogik investiert haette.

Das war einer der Hauptgruende, warum ich nach einer schlankeren Option gesucht habe.

Warum Fastify fuer mich besser funktioniert hat

Der Wechsel zu Fastify fuehlte sich wie frische Luft an. Es bietet die wesentliche HTTP-Server-Funktionalitaet, ohne ein grosses Architekturmodell auf die Anwendung zu legen.

Fastify ist schnell, leichtgewichtig und explizit. Es gibt mir Routing, Plugins, Schema-Validation, Hooks und ein starkes Oekosystem, zwingt mich aber nicht, die gesamte Anwendung um Decorators oder einen Dependency-Injection-Container herum zu strukturieren.

Kombiniert mit TypeScript und DDD bekomme ich weiterhin eine saubere Architektur, aber mit weniger framework-erzwungenen Schichten.

Klare Struktur ohne Framework-Gewicht

Die Struktur, die ich bevorzuge, ist einfach:

  • Controller fuer HTTP-Request- und Response-Handling,
  • Services fuer Application- und Business-Use-Cases,
  • Repositories fuer Datenzugriff,
  • Domain Objects und Value Objects fuer zentrale Business-Regeln,
  • Infrastructure Adapter fuer externe Systeme.

Das haelt die Architektur organisiert, ohne das Framework zum Zentrum des Codebases zu machen.

In einem Fastify-Projekt kann ein Controller einfach ein Route Handler sein, der einen Application Service aufruft. Ein Repository kann ein normales TypeScript-Modul oder eine Klasse sein. Ein Domain Service kann framework-unabhaengig bleiben.

Diese Trennung ist wichtig, weil die Business-Logik nicht vom HTTP-Framework abhaengen sollte.

Einfacheres Debugging

Mit weniger Decorators und Wrappers zeigen Fehler meist direkter auf die relevante TypeScript-Datei.

Der Request-Flow ist leichter nachvollziehbar:

  1. Eine Fastify-Route nimmt den Request entgegen.
  2. Der Controller validiert oder mappt die Eingabe.
  3. Der Service fuehrt den Use Case aus.
  4. Repository oder Adapter uebernimmt Persistenz oder externe Calls.
  5. Der Controller gibt die Response zurueck.

Dazwischen gibt es weniger versteckte Mechanik. Fuer meinen Arbeitsstil macht das Debugging und Refactoring einfacher.

Weniger Dependency-Kopfschmerzen

Fastify selbst ist leichtgewichtig, und Updates fuehlen sich normalerweise einfacher an. Eine kleinere Framework-Oberflaeche bedeutet weniger Stellen, an denen Versionskonflikte auftreten koennen.

Das heisst nicht, dass Fastify-Projekte keine Dependencies haben. Natuerlich haben sie welche. Aber der Dependency Graph fuehlt sich kontrollierbarer an, weil die Architektur nicht um ein grosses Framework-Oekosystem herum gebaut ist.

Fuer kleine und mittlere Services zaehlt dieser reduzierte Overhead.

Warum ich weiterhin auf DDD setze

Nest.js zu verlassen bedeutete nicht, Struktur aufzugeben. Ich setze weiterhin stark auf Domain Driven Design.

DDD bedeutet nicht, ein fancy Framework zu verwenden. Es bedeutet, Software um die zentrale Business-Logik herum zu entwerfen. Die wichtigsten Teile des Systems sollten die Business-Sprache ausdruecken, nicht Framework-Interna.

Auch nach dem Abschied von Nest.js behalten meine Backend-Projekte ein DDD-freundliches Layout:

  • Repositories fuer Datenzugriff,
  • Services fuer Business-Workflows,
  • Domain Models fuer zentrale Regeln,
  • Controller fuer API-Endpunkte,
  • Adapter fuer Infrastrukturthemen.

Der Unterschied ist, dass ich nicht mehr den Overhead mitschleppe, den Nest.js fuer meine Use Cases eingefuehrt hat.

Wann Nest.js weiterhin Sinn ergibt

Ich denke nicht, dass Nest.js nutzlos ist. Es kann gut zu Teams passen, die ein voll ausgestattetes Enterprise-Framework wollen, besonders wenn sie aus Java, Spring, C# oder Angular-aehnlicher Architektur kommen.

Es kann auch helfen, wenn ein grosses Team strenge Konventionen und konsistente Patterns ueber viele Services hinweg braucht.

Fuer manche Organisationen ist dieser Tradeoff sinnvoll.

Aber fuer Teams, die Flexibilitaet, schlanken Code und direkte Kontrolle ueber die Anwendungsarchitektur schaetzen, kann Fastify mit DDD besser passen.

Mein Fazit

2025 wurde mir klar, dass Nest.js fuer mich nicht mehr der richtige Default war. Es gab Struktur, brachte aber auch Komplexitaet, Debugging-Reibung und Dependency-Overhead mit, den ich nicht in jedem Backend-Projekt wollte.

Fastify gab mir die HTTP-Basis, die ich brauchte, waehrend DDD mir die Architektur gab, die ich wollte.

Diese Kombination haelt den Code explizit, testbar und leichter nachvollziehbar. Sie erlaubt ausserdem, dass das Domain Model unabhaengig vom Framework bleibt.

Fuer meine Backend-Arbeit war das der bessere Tradeoff.