Nub im Überblick: das All-in-One-Toolkit für Node.js
Nub ist ein Rust-Toolkit für Node.js, das TypeScript, Scripts, Installationen und Node-Versionen auf dem Standard-Node ausführt und Lockfiles sowie Sicherheitsprüfungen behält.
Nub ist ein in Rust geschriebenes Kommandozeilen-Toolkit für Node.js. Es transpiliert TypeScript, führt package.json-Skripte aus, installiert Abhängigkeiten und stellt Node-Versionen bereit – die Ausführung selbst übergibt es anschließend an die reguläre node-Binary, die Ihr Projekt ohnehin festgelegt hat. Es erweitert Node, statt es zu ersetzen, und genau darin liegt der Unterschied zu Bun oder Deno.
Die meisten Teams, die Bun und Deno gegen Node abgewogen haben, kamen über die erste Frage nie hinaus: Man tauscht die Runtime unter einem Produktivdienst nicht aus, nur weil die Developer Experience angenehmer ist. Nub geht den anderen Weg und bezeichnet sich selbst als Rust-Toolkit, das Ihr Node, Ihre Lockfile und Ihren Package Manager unangetastet lässt. Im Folgenden geht es darum, was Ihnen das bringt – und was ein Versuch kostet.
Die wichtigsten Erkenntnisse
- Nub ist ein Rust-CLI, das TypeScript-Ausführung, Skript-Dispatch, Paketinstallation und Node-Versionsverwaltung auf die reguläre
node-Binary aufsetzt – eine neue Runtime muss also nicht freigegeben werden. - Nodes eigene TypeScript-Unterstützung entfernt lediglich Annotationen und lehnt alles ab, wofür Code generiert werden müsste, etwa Enums, Parameter Properties oder Namespaces mit Laufzeitcode; der Loader von Nub kompiliert diese Konstrukte stattdessen.
- Der Installer von Nub ist pnpm-artig aufgebaut und liest und schreibt bestehende npm-, pnpm- und bun-Lockfiles an Ort und Stelle; yarn-Lockfiles werden nur gelesen.
- Die Schutzmechanismen bei der Installation erfordern keinerlei Konfiguration: Build-Skripte von Abhängigkeiten bleiben blockiert, bis Sie sie freigeben, jede neue Auflösung wird gegen OSV geprüft, und eine 24-Stunden-Sperre nach Veröffentlichung hält brandneue Versionen fern.
- Es gibt keine Nub-spezifischen APIs und keine Nub-Lockfile, und
nub.jsoncist optional – wird Nub entfernt, läuft das Projekt wieder mit reinem Node.
Was ist Nub – und was ist es nicht?
Nub ist keine vierte Runtime. Es ist eine einzelne Binary, die sich vor Node schaltet, die Arbeit erledigt, für die derzeit tsx, nvm, npx und ein Package Manager nötig sind, und anschließend echtes Node per exec startet. Die Homepage beschreibt den Mechanismus unmissverständlich: oxc kompiliert Ihre Dateien innerhalb eines nativen Addons im Speicher, und die reguläre node-Binary führt das Ergebnis aus. Darunter liegt keine separate Runtime, und der File Runner akzeptiert dieselben Flags wie node.
An Ihrem Deployment-Ziel ändert sich nichts. Die V8-Version, das C++-ABI, gegen das Ihre nativen Module gebaut wurden, die process-Oberfläche, an der Ihr Instrumentierungs-Hook hängt – all das entspricht dem Node, das Sie ohnehin ausgeliefert haben. Der augmentierte Pfad setzt Node 18.19 oder neuer (Node 18 LTS) voraus, unter macOS, Linux und Windows, jeweils auf x64 und arm64.
Das Projekt steht noch am Anfang. Das npm-Paket @nubjs/nub ist unter MIT veröffentlicht und weiterhin pre-1.0, zum aktuellen Release auf der 0.9.x-Linie, mit häufig erscheinenden neuen Versionen.
Wie führt Nub TypeScript ohne Build-Schritt aus?
Nodes eigene TypeScript-Unterstützung entfernt Typen, statt sie zu kompilieren. Annotationen werden durch Leerzeichen ersetzt, und alles, wofür JavaScript generiert werden müsste, wird abgelehnt. Die Node-Dokumentation listet die Fälle auf: Enums, Namespaces mit Laufzeitcode, Parameter Properties und import =-Aliase lösen sämtlich ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX aus; Decorators scheitern beim Parsen; und da Node tsconfig.json nie öffnet, werden paths-Aliase nicht angewendet. Ein vollständigerer Transform-Modus lag früher hinter --experimental-transform-types, doch Node hat dieses Flag in Version 26 entfernt – die Erasure ist damit der einzige eingebaute Weg.
Genau diese Ausschlüsse betreffen die Syntax, aus der eine NestJS- oder TypeORM-Codebasis besteht. Nehmen wir eine Datei mit einem Enum, einer Parameter Property und einem relativen Import ohne Dateiendung:
// invoice.ts
import { Model } from "./base"
enum Status { Draft, Sent, Paid }
export class Invoice extends Model {
constructor(public status: Status = Status.Draft) {
super()
}
}
Mit einfachem node invoice.ts sind Enum und Parameter Property nicht erasable, und der Import hat keine Dateiendung. Mit nub invoice.ts läuft dieselbe Datei unverändert. Nub übergibt jede Datei zum Kompilieren an sein natives Addon – deshalb funktionieren Enum, Parameter Property und der Import ohne Endung. Zusätzlich wertet es Ihre tsconfig.json sowie jede per extends eingebundene Konfiguration aus und reicht die paths-Aliase über einen module.registerHooks()-Resolve-Hook an Nodes eigenen Resolver weiter.
Decorators werden nur in einer Ausprägung unterstützt. Der Launch-Beitrag behandelt die Legacy-Variante experimentalDecorators, also die Form, gegen die NestJS, TypeORM und Angular geschrieben sind, samt emitDecoratorMetadata. Stage-3-Decorators, die TypeScript 5 standardmäßig verwendet, werden abgelehnt, weil der Transform in oxc noch eine offene Lücke ist. Der Runner erzeugt Inline-Source-Maps, sodass Stack Traces auf Ihren Quellcode zeigen und nicht auf generierte Ausgabe. Dieses Detail ist nicht bloß Kosmetik: Transpiliertes TypeScript, das seine Source Maps verliert, produziert Traces gegen Code, den niemand geschrieben hat – eine wiederkehrende Quelle verschwendeter Triage-Zeit.
Welche Befehle ersetzt Nub?
Die einzelne Binary von Nub deckt Aufgaben ab, die derzeit auf ein ganzes Regal an Werkzeugen verteilt sind. Die dokumentierte Zuordnung ist eindeutig:
| Nub-Befehl | Ersetzt |
|---|---|
nub <file> | node, tsx, ts-node, dotenv-cli |
nub run <script> | npm run, pnpm run, yarn run |
nubx | npx, pnpm dlx, pnpm exec, yarn dlx |
nub install | npm, pnpm, yarn |
nub watch | nodemon, node --watch, tsx watch |
nub node | nvm, fnm, n, volta |
nub pm | corepack |
Diese Tabelle deckt nicht den gesamten Funktionsumfang ab. Die README behandelt zusätzlich nubr, einen einzelnen Befehl, der eine Datei, ein package.json-Skript oder eine Bin aus node_modules/.bin ausführt – und zwar in genau dieser Reihenfolge. Für Projekte, die keine Binary installieren können, gibt es ihn eigenständig als @nubjs/runner.
Entscheidend ist, dass diese Bestandteile unabhängig voneinander sind. Wer den File Runner übernimmt, muss nicht auch den Installer übernehmen, und wenn Sie ein dev-Skript von tsx watch src/server.ts auf nub watch src/server.ts umstellen, bleibt package.json ein ganz normales, npm-kompatibles Manifest. Für die Geschwindigkeitsangaben verweist das Projekt auf eigene Benchmarks: 24× schneller als pnpm run beim Skript-Dispatch, 19× schneller als npx bei der Bin-Ausführung und 18× schneller als pnpm install. Die gepaarten Messwerte der README nennen 14,7 ms für den Skript-Dispatch gegenüber 329,9 ms bei npm sowie 171 ms für eine warme Frozen-Installation gegenüber 3193 ms bei pnpm, beides unter macOS gemessen. Ein zweiter Installations-Benchmark, mit hyperfine auf einem ubuntu-latest-Runner gegen einen Baum mit 1.168 Paketen ausgeführt, weist 346 ms für Nub und 3453 ms für pnpm aus.
Der Package Manager: pnpm-artig und lockfile-erhaltend
Der Installer von Nub führt kein eigenes Lockfile-Format ein. Er ermittelt anhand von package.json#packageManager oder der vorgefundenen Lockfile, welchen Package Manager das Projekt bereits verwendet, läuft dann im Compat-Modus und respektiert die Konfigurationsdateien und Umgebungsvariablen dieses Werkzeugs. Das CLI selbst ist pnpm-artig aufgebaut, sodass sich nub install, nub add -E -D react, nub remove, nub update und nub ci so verhalten, wie es die Muskelgedächtnis-Erwartung vorgibt.
Speziell zu den Lockfiles: npm-, pnpm- und bun-Lockfiles werden an Ort und Stelle gelesen und geschrieben, yarn-Lockfiles nur gelesen. Es wird nichts konvertiert, und im Diff taucht keine zweite Lockfile auf. Für ein Team auf pnpm ist genau das die Frage, die darüber entscheidet, ob eine Evaluierung überhaupt infrage kommt.
Auflösung der Node-Version ohne nvm
nub node ermittelt die Node-Version, die ein Projekt erwartet, und stellt sie bei Bedarf bereit. Die Version stammt aus .node-version, .nvmrc oder package.json#engines; eine fehlende Version wird automatisch heruntergeladen und zwischengespeichert. Explizite Befehle gibt es ebenfalls: nub node install 26, nub node ls, nub node pin 26 und nub node uninstall 22. Das geschieht ohne Shell-Hooks und ohne Umschreiben Ihres PATH – also ohne genau den Teil von nvm, der in CI-Umgebungen und nicht-interaktiven Shells gern bricht.
Supply-Chain-Voreinstellungen und das Fehlen von Lock-in
Die Schutzmechanismen von Nub zur Installationszeit sind ohne Konfiguration aktiv. Vier davon sind dokumentiert. Die Build-Skripte einer Abhängigkeit laufen erst, wenn Sie das jeweilige Paket freigeben. Jede neue Auflösung wird gegen OSV auf bekannte bösartige Versionen geprüft. Eine Version, die den Publishing-Trust-Nachweis eines früheren Releases verloren hat, wird rundweg abgelehnt. Und minimumReleaseAge steht standardmäßig auf 24 Stunden – dasselbe Zeitfenster, das pnpm verwendet –, sodass eine vor Minuten veröffentlichte Version nicht in Ihren Abhängigkeitsbaum gelangt. Der Launch-Beitrag ergänzt, dass eine transitive Abhängigkeit, die auf eine git+-, file:- oder reine Tarball-URL aufgelöst wird, abgelehnt statt stillschweigend geladen wird. Wer bereits eine Verteidigungsstrategie gegen npm-Supply-Chain-Angriffe erarbeitet hat, findet hier genau diese Checkliste als Standardverhalten wieder – statt als selbst gepflegte .npmrc.
Die zweite Hälfte ist die Umkehrbarkeit. Nub fügt keine APIs zum Importieren hinzu, schreibt keine eigene Lockfile und behandelt nub.jsonc als optionale Konfiguration, nicht als Pflicht. Deinstallieren Sie die Binary, läuft das Projekt mit reinem Node und dem vorherigen Tooling weiter – weil der Quellcode Nub nie referenziert hat.
Wer sollte Nub ausprobieren – und wer nicht?
Probieren Sie es aus, wenn Sie TypeScript über tsx oder ts-node ausführen, nvm für das Versions-Pinning vorhalten und nicht gleich ein Quartal damit verbringen möchten, eine neue Runtime freizugeben, nur um da herauszukommen. Beginnen Sie mit dem File Runner in einem einzelnen Dienst, lassen Sie den Installer vorerst außen vor, und prüfen Sie, ob die Build-Schritt-Reibung rund um Enums und Decorators verschwindet. Lassen Sie es vorerst bleiben, wenn Sie für einen regulierten Release-Prozess eine festgepinnte, langweilige Toolchain brauchen – denn ein Pre-1.0-Projekt, das im Abstand von Tagen Releases veröffentlicht, ist das noch nicht. Der Preis für die Antwort beträgt npm install -g @nubjs/nub und einen einzelnen Befehl gegen eine Datei, die Sie ohnehin schon haben.
FAQs
Wie führe ich eine Datei ganz ohne Augmentierung über Nub aus?
Verwenden Sie den Kompatibilitätsmodus: Übergeben Sie --node für einen einzelnen Aufruf, oder setzen Sie NODE_COMPAT auf 1, true oder yes, um den gesamten Prozessbaum abzudecken. In diesem Modus wendet Nub überhaupt nichts an – es gibt keinen Load-Hook, kein Preload, keine Flag-Injection und kein .env-Laden. Es ermittelt weiterhin, welches Node das Projekt festlegt, und installiert es bei Bedarf, sodass Ihr Code unverändert auf der richtigen Version läuft. Das ist nützlich, um einen Nub-Bug von einem Node-Bug zu unterscheiden.
Welche Plattformen und Node-Versionen unterstützt Nub?
Nub liefert vorgebaute Rust-Binaries für Linux, macOS und Windows auf x64 und arm64 aus und zieht bei der Installation das passende N-API-Addon für Ihre Plattform nach. Augmentierte Modi benötigen Node 18.19 oder neuer, weil dort die Loader-Hook-API erstmals auftaucht, auf der der Transpile-on-Import-Pfad beruht. Auf älteren Versionen bricht ein augmentierter Befehl mit einem Fehler ab, der die Mindestversion nennt und auf den Kompatibilitätsmodus verweist.
Warum schlägt eine Installation mit ERR_NUB_ALLOW_BUILDS_RENAMED fehl?
Nub 0.9.0 hat die Top-Level-Build-Allowlist in package.json von allowBuilds in allowScripts umbenannt, passend zu dem Feld, das npm 12 ausliest. Ein Projekt, das noch eine allowBuilds-Map auf Root-Ebene enthält, wird mit diesem Fehler abgelehnt statt nur gewarnt – die Lösung besteht also darin, den Schlüssel umzubenennen. Ein allowBuilds von pnpm ist eine andere Einstellung und bleibt unangetastet, egal ob es in pnpm-workspace.yaml oder unter package.json#pnpm steht.
Kann ich nubx nutzen, ohne den Package Manager zu wechseln?
Ja. nubx findet ein lokal installiertes CLI in node_modules/.bin, unabhängig davon, was es dort abgelegt hat. Es funktioniert also in einem Projekt, das mit npm, pnpm, yarn oder bun installiert wurde, ohne dass etwas migriert werden muss. Es akzeptiert die Flags von pnpm exec unter denselben Namen, und nub dlx bildet pnpm dlx bis hin zum Shell-Modus nach, sodass vorhandene Befehlszeilen übernommen werden können.
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