Using Modern Node.js Features

1. Native Fetch API v18+ stable v21

Example

const res = await fetch("https://api.example.com/users", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ name: "Ada" }),
  signal: AbortSignal.timeout(5000)
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
Backed byNotes
undiciHTTP/1.1 client; HTTP/2 via separate API
Request / Response / Headers / FormData / BlobAll global

2. Top-Level Await

Example: only in ESM

// index.mjs (or "type":"module")
const config = await loadConfig();
export { config };

3. Import Assertions / Attributes

Example: Import Attributes v22+

import data from "./data.json" with { type: "json" };
// Older: with → assert (deprecated)
const mod = await import("./cfg.json", { with: { type: "json" } });

4. Web Streams API

Example: ReadableStream → fetch upload

const stream = new ReadableStream({
  start(controller) { controller.enqueue("hi"); controller.close(); }
});
await fetch(url, { method: "POST", body: stream, duplex: "half" });

5. AbortController and AbortSignal

Example

const ac = new AbortController();
setTimeout(() => ac.abort(new Error("timeout")), 1000);
await fetch(url, { signal: ac.signal });

// Helpers
AbortSignal.timeout(2000);
AbortSignal.any([sigA, sigB]);

6. structuredClone

Example

const copy = structuredClone({
  date: new Date(),
  set: new Set([1, 2]),
  buf: new ArrayBuffer(8)
});
SupportsDetail
Cyclic refsYes
Map/Set/Date/Regex/TypedArrayYes
Functions / DOM nodesNo (throws)

7. Test Runner (node:test) v18+ stable

Example

import { test } from "node:test";
import assert from "node:assert/strict";
test("greet", () => assert.equal(greet("Ada"), "hi Ada"));
RunCommand
Discovernode --test
Watchnode --test --watch
Coveragenode --test --experimental-test-coverage

8. Watch Mode (--watch)

FlagEffect
node --watch app.jsRestart on file changes v18+
node --watch-path=./src app.jsLimit watch scope
node --env-file=.envLoad .env without dotenv v20+

9. Built-In WebSocket Client v22+

Example

const ws = new WebSocket("wss://echo.websocket.events");
ws.addEventListener("open", () => ws.send("hello"));
ws.addEventListener("message", (e) => console.log(e.data));
Note: No flag required as of v22.4; earlier required --experimental-websocket.

10. REPL Enhancements

FeatureDetail
Top-level awaitEnabled in REPL
Auto-completionTab on globals, locals, properties
Reverse history searchCtrl+R
.editorMulti-line edit mode
.load / .saveLoad / save sessions
NODE_REPL_HISTORYPersistent history file

Bonus: Single Executable Apps (node:sea) v20+

Build Workflow

  1. Write sea-config.json referencing your bundled JS
  2. node --experimental-sea-config sea-config.json → produces blob
  3. Copy node binary, inject blob via postject
  4. Codesign (macOS) / sign (Windows)
  5. Ship a single binary with no Node install required