Node.js 24 Features That Improve Developer Experience

March 2, 2026, by Nicolas Even

What we want to do

Run TypeScript files directly:

node index.ts

Use ES Modules and Top Level awaits:

import { transform } from "./transform.ts";
import { readFile } from "fs/promises";

const f = await readFile("./file");
await transform(f);

Run tests:

node --test

Restart the process when the source files change:

node --watch index.ts

Read .env files without dotenv.

Read command-line arguments.

How to do it

Typescript, ES Modules and Top Level awaits

Create a package.json that looks like this:

{
  "type": "module",
  "scripts": {
    "test": "node --test",
    "start": "node index.ts"
  },
  "devDependencies": {
    "@types/node": "^24.0.14",
    "typescript": "^5.8.3"
  }
}

The important line above is "type": "module". It enables ES Modules by default, without having to use the .mts extension.

Create a tsconfig.json that looks like that:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "rewriteRelativeImportExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

The most important options here are:

These options not only make sure the code is compiled correctly, but also make autocompletion work as expected (for ex. auto-creating the import statements with the .ts extension, or automatically adding the type qualifier to the imports).

Limitations:

When running node index.ts, Node.js erases the type information. This means:

Tests

Just create test files:

// operations.test.ts
import test from "node:test";
import { strictEqual } from "node:assert";
import { add } from "./operations";

test("addition", () => {
  strictEqual(add(1, 2), 3);
});

.env files

import { loadEnvFile } from "node:process";
loadEnvFile();

An alternative way to do that is to use parseEnv, but it doesn’t merge the environment into process.env:

import { parseEnv } from "node:util";
import { readFile } from "node:fs/promises";

const env = await parseEnv(await readFile(".env", "utf-8"));

Command-Line arguments

import { parseArgs } from "node:util";
import { argv } from "process";

const {
  values: { url, timeout },
} = parseArgs({
  args: argv.slice(2),
  options: {
    url: { type: "string" },
    timeout: { type: "string", default: "600" },
  },
});

The function is pretty basic (it doesn’t support required arguments, doesn’t generate a --help command), but it’s largely good enough for small scripts.

Restart your server when the source files change

No setup required 🎉, just run:

node --watch index.ts