Layer 8Ehrlicher Tech-Support

Node.js: __dirname ist in ES-Modulen nicht definiert

Nach type module in der package.json fehlt __dirname? ES-Module kennen die Variable nicht. Node bietet dafür import.meta.dirname an.

Aufwand:
ca. 15 Min.
Voraussetzung:
Node.js ab v20.11.0 bzw. v21.2.0 für import.meta.dirname, Ein Texteditor für package.json und Quelltext
Gilt für:
Node.js v26.12.0 (Dokumentation abgerufen am 15.10.2026); import.meta.dirname und import.meta.filename hinzugefügt in v21.2.0 und v20.11.0, nicht mehr experimentell seit v24.0.0 und v22.16.0

Das Symptom

Ein Node-Projekt soll modernisiert werden. Jemand ergänzt in der package.json das Feld type mit dem Wert module, damit man überall import statt require schreiben kann, und stellt die Imports um. Beim nächsten Start bricht das Programm ab: __dirname sei nicht definiert. Die Zeile, an der es scheitert, hat sich seit Jahren nicht verändert. Sie baut wie immer den Pfad zu einer Vorlage, einer Konfigurationsdatei oder einem Ordner mit statischen Dateien.

Die Suche nach der Ursache führt zunächst in die falsche Richtung. Es wird vermutet, Node sei kaputt aktualisiert worden, eine Bibliothek habe etwas überschrieben oder der Bundler mache Ärger. Manche setzen am Dateianfang einfach selbst eine Variable __dirname mit einem festen Pfad, damit es wieder läuft, und wundern sich später auf dem Server.

Die „Layer 8“-Wahrheit

Node kennt zwei Modulsysteme, und __dirname gehört nur zu einem davon. Die Dokumentation für CommonJS beschreibt __dirname als eine der Annehmlichkeiten des Modulbereichs, „The directory name of the current module“. Für ES-Module steht in der Liste der Unterschiede zu CommonJS ein eigener Abschnitt, und er ist kurz: „These CommonJS variables are not available in ES modules.“ Gemeint sind __filename und __dirname.

Welches der beiden Systeme gilt, entscheidet nicht der Inhalt der Datei allein, sondern ihre Kennzeichnung. Die Paket-Dokumentation nennt die Endungen .mjs und .cjs sowie das Feld type in der package.json als ausdrückliche Markierungen. Steht dort module, wird jede .js-Datei darunter als ES-Modul geladen. Die eine Zeile in der package.json hat also nicht nur die Schreibweise der Imports erlaubt, sondern stillschweigend alle Dateien in ein anderes Modulsystem verschoben, in dem eine alte Gewohnheit nicht mehr existiert.

Der Ersatz ist seit einiger Zeit eingebaut. Die Dokumentation sagt: „__filename and __dirname use cases can be replicated via import.meta.filename and import.meta.dirname.“ Beide Eigenschaften kamen mit v21.2.0 und v20.11.0 und gelten seit v24.0.0 und v22.16.0 nicht mehr als experimentell. Wer eine ältere Version betreibt, bestimmt den Ordner aus import.meta.url über fileURLToPath, denn import.meta.filename ist laut Dokumentation genau das. Und wer eine einzelne Datei beim alten Stil lassen will, gibt ihr die Endung .cjs.

Der eigentliche Fehler ist also keiner im Code, sondern einer in der Erwartung: dass eine Variable, die man jahrelang benutzt hat, zur Sprache gehört. Sie gehörte zum Modulsystem. Mit dem Wechsel des Modulsystems ist sie weg, und der fest eingetragene Pfad, der die Meldung zum Schweigen bringt, verschiebt den Fehler nur auf den nächsten Rechner.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Feststellen, ob die Datei ein ES-Modul ist

    Node behandelt laut Dokumentation Dateien mit der Endung .mjs als ES-Modul, Dateien mit .cjs als CommonJS, und .js-Dateien nach dem Feld type der nächsten übergeordneten package.json. Steht dort module, ist jede .js-Datei darunter ein ES-Modul. Die Dokumentation nennt die Endungen .mjs und .cjs sowie das Feld type ausdrücklich als „Explicit markers“. Ein Blick in die package.json klärt also, warum __dirname plötzlich fehlt.

    cat package.json
    
  2. 2.

    import.meta.dirname verwenden

    In einem ES-Modul ersetzt import.meta.dirname die alte Variable __dirname und import.meta.filename die Variable __filename. Beide liefern Pfade im Dateisystem, nicht Adressen. Wer damit Pfade zu Nachbardateien baut, nimmt wie gewohnt path.join. Voraussetzung ist eine Node-Version ab v20.11.0 oder v21.2.0; seit v24.0.0 und v22.16.0 sind die Eigenschaften nicht mehr experimentell.

    import path from 'node:path';
    const vorlage = path.join(import.meta.dirname, 'vorlagen', 'mail.html');
    
  3. 3.

    Für ältere Node-Versionen den Umweg über import.meta.url nehmen

    Ältere Versionen kennen import.meta.dirname nicht. Dann wandelt fileURLToPath aus node:url die file:-Adresse aus import.meta.url in einen Dateipfad, und dirname aus node:path schneidet den Dateinamen ab. Die Dokumentation beschreibt import.meta.filename genau als das Ergebnis von url.fileURLToPath() auf import.meta.url. Das Ergebnis entspricht damit dem, was __dirname in CommonJS geliefert hätte.

    import { fileURLToPath } from 'node:url';
    import { dirname } from 'node:path';
    const ordner = dirname(fileURLToPath(import.meta.url));
    
  4. 4.

    Oder die Datei bewusst als CommonJS führen

    Muss eine einzelne Datei beim alten Stil bleiben, etwa ein Werkzeug, das require und __dirname überall benutzt, lässt sie sich mit der Endung .cjs ausdrücklich als CommonJS kennzeichnen, auch wenn die package.json type auf module setzt. Dort sind __dirname und __filename laut Modul-Dokumentation die gewohnten Variablen. Umgekehrt braucht ein ES-Modul ein require nur selten; wenn doch, lässt es sich laut Dokumentation mit module.createRequire() erzeugen.

  5. 5.

    Nicht einfach die Fehlermeldung wegdefinieren

    Eine selbst gesetzte Variable namens __dirname mit einem festen Pfad lässt die Meldung verschwinden, funktioniert aber nur auf dem Rechner, auf dem der Pfad stimmt. Spätestens im Container oder auf dem Server zeigt sie ins Leere, und der Fehler kommt als fehlende Datei zurück, weit weg von seiner Ursache. Der saubere Weg ist einer der drei oben, je nach Node-Version und je nachdem, ob die Datei ein ES-Modul bleiben soll.

Häufige Fragen (FAQ)

?Warum ging es gestern noch und heute nicht mehr?

Weil sich vermutlich nicht der Code geändert hat, sondern die Art, wie Node ihn liest. Die Dokumentation zu Paketen beschreibt, dass eine Datei mit der Endung .js als ES-Modul behandelt wird, wenn die nächste übergeordnete package.json ein Feld type mit dem Wert module enthält. Wer dieses Feld ergänzt hat, etwa um import statt require zu schreiben, hat damit alle .js-Dateien darunter zu ES-Modulen gemacht. Und in ES-Modulen gibt es __dirname nicht; die Dokumentation sagt über __filename und __dirname: „These CommonJS variables are not available in ES modules.“

?Was ist der offizielle Ersatz?

import.meta.dirname und import.meta.filename. Die Node-Dokumentation schreibt: „__filename and __dirname use cases can be replicated via import.meta.filename and import.meta.dirname.“ import.meta.dirname ist laut Dokumentation „The directory name of the current module“ und entspricht path.dirname() von import.meta.filename. Beide Eigenschaften gibt es seit v21.2.0 und v20.11.0; seit v24.0.0 und v22.16.0 sind sie nicht mehr als experimentell gekennzeichnet.

?Mein Node ist älter. Gibt es einen anderen Weg?

Ja, über import.meta.url, das die Dokumentation als absolute file:-Adresse des Moduls beschreibt. Für import.meta.filename heißt es dort, es sei dasselbe wie url.fileURLToPath() von import.meta.url. Mit fileURLToPath aus node:url und dirname aus node:path lässt sich der Ordner also auch ohne die neuen Eigenschaften bestimmen. Für relative Dateien zeigt die Dokumentation zudem das Muster new URL('./datei', import.meta.url), das ganz ohne Ordnernamen auskommt.

?Warum fehlt import.meta.dirname manchmal trotzdem?

Weil es nur für Module existiert, die als Datei geladen wurden. Die Dokumentation vermerkt bei import.meta.dirname ausdrücklich als Vorbehalt, die Eigenschaft sei „only present on file: modules.“ Bei import.meta.filename heißt es entsprechend, nur lokale Module unterstützten diese Eigenschaft, Module ohne file:-Protokoll stellten sie nicht bereit. Wer Code etwa als Zeichenkette über --eval ausführt oder aus einer anderen Quelle lädt, kann sich darauf nicht verlassen.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigJavaScript heap out of memory

Node.js: JavaScript heap out of memory

Der Build bricht mit „heap out of memory“ ab? Node hat ein festes Speicherlimit — man kann es anheben, sollte aber zuerst nach der Ursache suchen.