Engineering

Node.js 26

Apply Node.js 26 ESM, type-stripped execution, and runtime boundaries to build tools and servers.

Verified Source

Make ESM the explicit contract

In a "type": "module" package, include relative import extensions and derive file locations from import.meta.url. process.cwd() is the invocation location and should not be the sole anchor for a content script.

import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const currentDirectory = dirname(fileURLToPath(import.meta.url));
const contentRoot = resolve(currentDirectory, "../content");

Run TypeScript tools directly

Node 26 can execute .ts scripts that use erasable type syntax. Do not assume it transforms enums, parameter properties, or TypeScript path aliases. Application bundles still need framework compilation and tsc --noEmit.

Async I/O and failure

Use node:fs/promises and parallelize independent reads. Treat JSON and frontmatter as unknown, validate them, and only then construct internal models. A broken build contract should fail immediately with a precise path.

Practical tips

  • Use node: specifiers to distinguish built-ins.
  • Connect AbortSignal-aware APIs to request cancellation and shutdown.
  • Keep per-user mutable state out of server globals.
  • Update lockfile and runtime versions together, then run the full regression suite.

Failure cases

Implicitly mixing CommonJS and ESM

Interop and extension rules vary across environments. State the package format and export conditions, then verify with real Node execution.

Replacing type checking with type stripping

Successful execution is not a type check. Keep script execution and tsc --noEmit as separate gates.