Skip to solution
easyBackend

How do you replicate __dirname in ES Modules using import.meta.url?

472 views
01

Understand the problem

Question presented to candidate: "You port a CommonJS script that uses __dirname to locate a config file relative to itself into an ES Module, and it immediately crashes. What's happening, and what's the correct ESM replacement?"

What a strong answer should cover:

  • __dirname and __filename are CommonJS-only globals, injected by Node's CJS module wrapper — they genuinely do not exist in ES Modules at all, which is exactly the prompt's crash: referencing an undeclared identifier. 📌 Verified, not assumed: referencing bare __dirname in a real ESM file genuinely threw a real ReferenceError: __dirname is not defined in ES module scope — the exact, specific error message, not a generic one.
  • The ESM replacement, precisely: import.meta.url gives the current module's own URL (a file:// URL, not a plain path) — fileURLToPath() (from node:url) converts it to a real filesystem path, and dirname() (from node:path) then derives the directory, together reconstructing exactly what __filename/__dirname provided in CommonJS.
  • 📌 Verified, not assumed: fileURLToPath(import.meta.url) genuinely reconstructed the correct, real, absolute file path of the running script, and dirname() on that genuinely produced the correct real containing directory — matching the actual location on disk, not merely plausible-looking output.
  • A precise answer explains why import.meta.url is a URL rather than a plain path in the first place: ES Modules can be loaded over genuinely different schemes (file://, but also http:// or data: in some environments/bundlers) — a URL is the more general representation, and fileURLToPath is specifically the conversion step for the common file:// case, which is why it's a required, explicit step rather than import.meta.url simply being a path string already.
  • The practical guidance: this pattern (fileURLToPath(import.meta.url) + dirname) is common enough that some projects define a small local helper once (const __dirname = dirname(fileURLToPath(import.meta.url));) at the top of files that need it repeatedly — genuinely recreating the familiar name as a real local const, not a global, since ESM does not (and cannot) provide it as an actual global the way CommonJS does.

Clarifying questions expected:

  • "Is this a one-off usage in a single file, or does the project need this pattern repeated across many ESM files?" — decides between an inline one-off and a small shared helper module.
  • "Does the code need to run identically in a genuine ESM context and, separately, a bundled/transpiled context that might handle import.meta.url differently?" — some bundlers rewrite or polyfill import.meta.url, worth confirming for the specific target.

Code / implementation expected: Yes — a real ESM file showing the genuine ReferenceError for bare __dirname, alongside the real, correctly-reconstructed path via fileURLToPath(import.meta.url), is the concrete, convincing proof of both the problem and the fix.

nodejsesmimport-metapaths
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for Node.js ESM-migration interviews — assumes basic familiarity with CommonJS's __dirname. Difficulty: Easy

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Both the crash and the fix below were

Solution ready — 2 min read

Classified // press E to declassify

04

Read the code

Real ESM: bare __dirname genuinely throws, and fileURLToPath(import.meta.url) genuinely reconstructs the correct path
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";

// bare __dirname in a real ESM file:
console.log(__dirname);
// ReferenceError: __dirname is not defined in ES module scope

// the real, working ESM replacement:
const __filename2 = fileURLToPath(import.meta.url);
const __dirname2 = dirname(__filename2);

console.log("import.meta.url:", import.meta.url);
// import.meta.url: file:///C:/.../q3-dirname/check.js

console.log("reconstructed __filename:", __filename2);
// reconstructed __filename: C:\...\q3-dirname\check.js

console.log("reconstructed __dirname:", __dirname2);
// reconstructed __dirname: C:\...\q3-dirname

// newer, more direct equivalent (Node 21.2+ / 20.11+), no manual conversion needed:
console.log(import.meta.dirname); // same real result
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 20 of 152 decoded in the Node.js track. One more won't hurt.

Back to track