12k
All articles

Einstieg in npm Workspaces

Einrichtung, Befehle und Grenzen von npm Workspaces: Monorepo verwalten, Sibling-Pakete verknüpfen und wissen, wann Turborepo oder Nx nötig ist.

OpenReplay Team
OpenReplay Team
Einstieg in npm Workspaces

npm Workspaces, seit npm Version 7 fest integriert, ermöglichen die Verwaltung mehrerer Pakete in einem einzigen Repository — einem Monorepo — von einem gemeinsamen Stammverzeichnis aus: Ein einziges npm install hebt gemeinsame Abhängigkeiten in ein zentrales node_modules hoch und verknüpft Ihre eigenen Pakete dort per Symlink, sodass paketübergreifende Importe ohne npm link und ohne erneutes Veröffentlichen aufgelöst werden. Wenn Sie eine App zusammen mit einer gemeinsamen Bibliothek oder eine Komponentenbibliothek mit ihrer Dokumentationsseite betreiben und es leid sind, mit npm link zu hantieren, Code zu kopieren oder separate Repositories zu verwalten, ist dies die integrierte Funktion, die diese Reibungspunkte beseitigt — ganz ohne Drittanbieter-Tools. Dieser Leitfaden behandelt die minimale Konfiguration, die genauen Befehls-Flags, die tatsächlichen Einschränkungen und den richtigen Zeitpunkt, einen Build-Orchestrator ergänzend einzusetzen.

Wichtigste Erkenntnisse

  • npm Workspaces sind ab npm 7+ enthalten; die aktuelle Version ist npm 11.18.0, und Sie können Ihre Version mit npm -v überprüfen.
  • Das minimale Setup besteht aus zwei Dateien: einer Root-package.json mit "private": true und "workspaces": ["packages/*"] sowie einer package.json pro Paket — ein einziges npm install im Stammverzeichnis verknüpft dann alles miteinander.
  • Um ein Geschwisterpaket als Abhängigkeit zu deklarieren, fügen Sie es mit dem Range-Wert "*" namentlich hinzu; npm verknüpft es bei der Installation per Symlink, sodass Änderungen am Quellcode sofort in jedem abhängigen Paket sichtbar sind — ohne Rebuild oder erneutes Veröffentlichen.
  • npm Workspaces lösen Abhängigkeiten auf und verknüpfen sie, führen jedoch keine Tasks in Abhängigkeitsreihenfolge aus, cachen keine Build-Ausgaben und berechnen keinen „Affected”-Graphen.
  • Setzen Sie Turborepo oder Nx zusätzlich zu npm Workspaces ein, nicht anstelle davon — npm löst Pakete auf und verknüpft sie; diese Tools ergänzen Task-Orchestrierung und Caching.

Wie funktionieren npm Workspaces?

npm Workspaces verwandeln ein einzelnes Repository in ein Monorepo, indem gemeinsame Abhängigkeiten in ein zentrales node_modules gehoben und Ihre eigenen Pakete dort per Symlink eingebunden werden. Wenn Sie npm install im Stammverzeichnis ausführen, durchsucht npm alle Workspaces, installiert Drittanbieter-Abhängigkeiten einmalig auf oberster Ebene und verknüpft jedes lokale Paket anhand seines name-Feldes in node_modules. Wenn zwei Ihrer Pakete voneinander abhängen, wird die Referenz über diesen Symlink aufgelöst — die npm CLI automatisiert die Verknüpfung als Teil von npm install und macht das manuelle Ausführen von npm link überflüssig.

Das gleiche workspaces-Feld und das Symlink-Modell werden auch von Yarn, pnpm und Bun verwendet, sodass das Konzept über Paketmanager hinweg übertragbar ist. Die Funktion wurde in npm 7 eingeführt; alle neueren Versionen unterstützen sie.

Was ist das minimale npm-Workspaces-Setup?

Das minimale Setup besteht aus zwei Dateien: einer Root-package.json, die angibt, wo die Pakete liegen, sowie einer package.json pro Paket. Erstellen Sie folgende Struktur:

my-monorepo/
├── package.json          # Root — privat, listet Workspaces auf
└── packages/
    ├── utils/
    │   └── package.json   # @myorg/utils
    └── app/
        └── package.json   # @myorg/app

Die Root-package.json benötigt zwei Felder:

{
  "name": "my-monorepo",
  "private": true,
  "workspaces": ["packages/*"]
}

"private": true verhindert, dass das Root-Paket versehentlich veröffentlicht wird, und der Glob packages/* weist npm an, jedes Verzeichnis unter packages/ als Workspace zu behandeln. Vergeben Sie jedem Paket einen Scoped-Namen wie @myorg/utils, um Kollisionen in der Registry zu vermeiden:

{
  "name": "@myorg/utils",
  "version": "1.0.0",
  "main": "dist/index.js"
}

Führen Sie npm install einmalig im Stammverzeichnis aus. Es gibt eine einzige Lockfile im Stammverzeichnis und kein node_modules innerhalb der einzelnen Pakete — alles wird nach oben gehoben.

Eine paketübergreifende Abhängigkeit hinzufügen

Um ein Geschwisterpaket als Abhängigkeit zu deklarieren, fügen Sie es mit dem Range-Wert "*" namentlich hinzu; npm verknüpft es bei der Installation per Symlink, sodass Änderungen am Quellcode sofort in jedem abhängigen Paket sichtbar sind. In @myorg/app:

{
  "name": "@myorg/app",
  "dependencies": {
    "@myorg/utils": "*"
  }
}

Führen Sie erneut npm install im Stammverzeichnis aus. npm erstellt einen Symlink von node_modules/@myorg/utils nach packages/utils, und Sie importieren es wie ein beliebiges veröffentlichtes Modul:

import { formatDate } from "@myorg/utils";

Da es sich um einen Symlink handelt, werden Änderungen am Quellcode in packages/utils in app ohne Rebuild oder erneutes Veröffentlichen übernommen — das ist der entscheidende Vorteil gegenüber npm link. Ein wichtiger Hinweis zur Tool-Kompatibilität: npm unterstützt nicht das workspace:-Versionsprotokoll, das pnpm und Yarn Berry verwenden. Die Angabe eines workspace:-Spezifizierers führt bei npm zu einem Fehler mit EUNSUPPORTEDPROTOCOL. Mit npm referenzieren Sie interne Pakete daher per Name und Range ("*"), nicht mit workspace:*.

Die täglichen Befehle

Die Flags sorgen häufig für Verwirrung, da Singular und Plural unterschiedliche Bedeutungen haben. Fügen Sie eine Abhängigkeit mit -w zu einem einzelnen Paket hinzu, mit --workspaces zu allen Paketen; führen Sie ein Skript mit -w in einem Workspace aus und mit --workspaces --if-present in allen — wobei Pakete ohne das jeweilige Skript übersprungen werden.

# Eine Abhängigkeit in EINEN Workspace installieren
npm install lodash -w @myorg/app

# Eine Dev-Abhängigkeit in einen Workspace installieren
npm install -D vitest -w @myorg/utils

# Eine Abhängigkeit in ALLE Workspaces installieren
npm install eslint --workspaces

# Ein Skript in EINEM Workspace ausführen
npm run build -w @myorg/utils

# Ein Skript in ALLEN Workspaces ausführen, fehlende überspringen
npm run test --workspaces --if-present

-w ist die Kurzform für --workspace, und --workspaces (oder -ws) adressiert alle Workspaces. Definieren Sie die Root-Skripte einmalig, damit npm run build auf alle Workspaces ausgeweitet wird:

{
  "scripts": {
    "build": "npm run build --workspaces --if-present",
    "test": "npm run test --workspaces --if-present"
  }
}

Um zu überprüfen, ob der Abhängigkeitsgraph korrekt verknüpft ist, führen Sie npm ls -ws aus oder fragen Sie ihn mit npm query .workspace ab.

Die Grenzen: Was npm Workspaces nicht leisten

npm Workspaces lösen Abhängigkeiten auf und verknüpfen sie, führen jedoch keine Tasks in Abhängigkeitsreihenfolge aus, cachen keine Build-Ausgaben und berechnen keinen „Affected”-Graphen. Wenn Ihre App eine Bibliothek importiert, müssen Sie die Bibliothek zuerst bauen — das Ausführen eines Skripts über alle Workspaces schlägt fehl, wenn diese voneinander abhängen, da npm nicht in topologischer Reihenfolge ausführt, ein Verbesserungsvorschlag, der noch offen ist. Legen Sie die Reihenfolge explizit fest oder verwenden Sie npm-run-all:

{
  "scripts": {
    "build:utils": "npm run build -w @myorg/utils",
    "build:app": "npm run build -w @myorg/app",
    "build": "npm run build:utils && npm run build:app"
  }
}

Zwei weitere Stolperfallen:

  • Verschachteltes node_modules. Wenn zwei Pakete inkompatible Versionen derselben Abhängigkeit benötigen, stoppt npm das Hoisting und installiert eine verschachtelte Kopie innerhalb eines Pakets. Legen Sie eine einzige gemeinsame Version über das overrides-Feld im Root fest, um den Abhängigkeitsbaum flach zu halten:

    { "overrides": { "lodash": "^4.17.21" } }
  • Installationsskripte werden standardmäßig eingeschränkt. npm v12, voraussichtlich im Juli 2026 veröffentlicht, ändert allowScripts so, dass es standardmäßig deaktiviert ist. npm install wird dann keine preinstall-, install- oder postinstall-Skripte von Abhängigkeiten mehr ausführen, sofern diese nicht explizit erlaubt werden. Wenn Ihre Workspaces auf einen postinstall- oder prepare-Build-Schritt angewiesen sind, planen Sie die entsprechende Freigabe ein — diese Änderungen werden ab npm 11.16.0 als Warnungen angezeigt, damit Sie sich frühzeitig vorbereiten können.

Der Hinweis „keine native React/Vue/Vite-Integration” ist eine Aussage über den Anwendungsbereich, kein Mangel: Workspaces sind bewusst framework-agnostisch konzipiert. Das Scaffolding von Apps ist nicht ihre Aufgabe.

Wann Turborepo oder Nx sinnvoll sind

Setzen Sie Turborepo oder Nx zusätzlich zu npm Workspaces ein, nicht anstelle davon: npm löst Ihre Pakete auf und verknüpft sie, während diese Tools Task-Orchestrierung, Caching und Affected-Graph-Builds für größere Repositories hinzufügen. Sie sind komplementäre Schichten.

Aspektnpm WorkspacesTurborepo / Nx
Pakete installieren & verknüpfenDelegiert an npm
Task-Abhängigkeitsreihenfolge❌ manuelle Skripte✅ topologisch
Build/Test-Caching✅ lokal + remote
„Affected”-Builds✅ änderungsbasierter Graph

Greifen Sie auf diese Tools zurück, wenn geordnete Skripte unhandlich werden, CI bei jeder Änderung alles neu baut oder Sie Tasks nur für die von einem Commit betroffenen Pakete ausführen möchten. Beachten Sie, dass das moderne Lerna nun Nx-basiert ist — der alte Ansatz „npm + Lerna” ist in dieses gleiche Schichtenmodell aufgegangen.

npm Workspaces decken etwa die ersten 80 % der Anforderungen kleiner Monorepos ohne zusätzliche Werkzeuge ab. Richten Sie die Zwei-Datei-Konfiguration ein, konfigurieren Sie Ihre Flags, legen Sie die Build-Reihenfolge fest und fügen Sie einen Orchestrator erst dann hinzu, wenn die Pipeline — nicht die Abhängigkeitsauflösung — zum Engpass wird. Verwenden Sie ein aktives LTS-Node-Release (Node 20 hat am 30.04.2026 sein End-of-Life erreicht) und stellen Sie sicher, dass npm -v Version 7 oder neuer ausgibt, bevor Sie beginnen.

Häufig gestellte Fragen

Benötigt npm Workspaces noch eine Lockfile pro Paket oder eine einzige im Stammverzeichnis?

npm Workspaces erzeugt eine einzige package-lock.json im Stammverzeichnis des Repositories, nicht eine pro Paket. Ein npm install im Root löst die Abhängigkeiten aller Workspaces gemeinsam auf und speichert sie in dieser einen Lockfile, während einzelne Pakete kein eigenes node_modules-Verzeichnis erhalten, da Abhängigkeiten in das Stammverzeichnis gehoben werden. Dieses Einzellockfile-Modell sorgt für konsistente Versionen über alle Pakete hinweg und ist der Grund, warum Sie die Installation stets vom Stammverzeichnis aus ausführen.

Warum schlägt 'npm run build --workspaces' fehl, wenn meine Pakete voneinander abhängen?

Der Fehler tritt auf, weil npm Workspace-Skripte nicht in topologischer (Abhängigkeits-)Reihenfolge ausführt, sondern in der Reihenfolge, in der Workspaces aufgelistet sind. Dadurch kann ein abhängiges Paket gebaut werden, bevor die importierte Bibliothek existiert, was zu Fehlern wie 'cannot find module' oder fehlgeschlagenen Auflösungen führt. Dies ist ein offener Verbesserungsvorschlag für npm (Issue 4139). Beheben Sie das Problem, indem Sie explizite geordnete Skripte definieren, die die Bibliothek zuerst bauen, oder indem Sie ein Tool wie npm-run-all, Turborepo oder Nx verwenden.

Kann ich das 'workspace:*'-Protokoll mit npm verwenden wie in pnpm oder Yarn?

Nein. npm unterstützt das workspace:-Versionsprotokoll von pnpm und Yarn Berry nicht, und die Angabe eines workspace:-Spezifizierers führt bei npm zu einem Fehler mit EUNSUPPORTEDPROTOCOL (dokumentiert in npm/cli Issue 8845). Mit npm referenzieren Sie interne Pakete über ihren Namen und einen normalen Range, z. B. '@myorg/utils': '*'; npm verknüpft sie bei der Installation per Symlink. Wenn Sie ein pnpm- oder Yarn-Repository zu npm migrieren, ersetzen Sie jeden workspace:-Spezifizierer durch einen einfachen Range.

Benötige ich noch 'npm link', wenn ich Workspaces verwende?

Nein. npm Workspaces automatisieren die Verknüpfung als Teil von npm install, indem jedes lokale Paket anhand seines name-Feldes per Symlink in das Root-node_modules eingebunden wird — das manuelle Ausführen von npm link wird damit überflüssig. Sobald ein Paket ein Geschwisterpaket mit dem Range '*' als Abhängigkeit deklariert, richtet ein einziges npm install im Stammverzeichnis den Symlink ein, und Änderungen am Quellpaket sind sofort in jedem abhängigen Paket sichtbar — ohne Rebuild oder erneutes Veröffentlichen.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.