- What "type stripping" means (and doesn't)
- Erasable vs non-erasable syntax
- Recommended tsconfig from Node's docs
- ESM vs CJS: you can't cheat it
- When to avoid type stripping
- Full TypeScript support with tsx
- Practical recipes you can copy/paste
Node.js can now run TypeScript directly—but there's an asterisk so big it should be on the homepage:
Node's built-in TS support is primarily type stripping, not full TypeScript compilation.
Node's own docs say there are two approaches: use a third-party package for full TypeScript features (including tsconfig.json), or use built-in support for lightweight type stripping.
What "type stripping" means (and what it doesn't)
| ✅ What It Does | ❌ What It Doesn't Do |
|---|---|
| Execute TS files with erasable syntax | Read or apply your tsconfig.json |
| Replace types with whitespace | Support path aliases |
| Run quickly without build step | Downlevel JS syntax (no "target ES2019") |
| — | Perform type checking |
Type stripping is "run TS-like files," not "compile TS projects."
The key detail: some TS syntax isn't erasable
Node's docs call out that transforming non-erasable TS syntax (like enum declarations or parameter properties) requires JS code generation and needs a flag:
node --experimental-transform-types src/index.ts
To disable stripping entirely: --no-strip-types
Example: erasable types (works with stripping)
// src/math.ts
export function add(a: number, b: number): number {
return a + b;
}
// Run it:
node src/math.ts
Example: non-erasable types (needs transform flag)
// src/status.ts
export enum Status {
Ok = 200,
NotFound = 404,
}
// Run with transform:
node --experimental-transform-types src/status.ts
Recommended tsconfig from Node's docs
Node recommends TypeScript 5.8+ and provides a tsconfig template tuned for type stripping:
{
"compilerOptions": {
"noEmit": true,
"target": "esnext",
"module": "nodenext",
"rewriteRelativeImportExtensions": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true
}
}
| Option | Purpose |
|---|---|
module: nodenext | Matches Node's ESM/CJS behavior expectations |
rewriteRelativeImportExtensions | Aligns TS imports with Node runtime resolution |
erasableSyntaxOnly | Keeps you from writing TS that requires compilation |
noEmit | For "runtime execution only" scripts |
ESM vs CJS: you can't cheat it
Node will not convert between module systems:
- Want ESM? Use
import/export - Want CommonJS? Use
require/module.exports
ESM example (recommended going forward)
// src/index.ts
import { add } from "./math.js"; // extension matters
console.log(add(1, 2));
CJS example
// src/index.cts
const { add } = require("./math.cjs");
console.log(add(1, 2));
When you should NOT use type stripping
| ✅ Use Type Stripping When | ❌ Avoid Type Stripping When |
|---|---|
| Writing scripts/tools | You rely on path aliases |
| You want fast iteration | You use decorators / emit transforms |
| Your TS stays "erasable only" | You expect tsconfig to change runtime |
| You don't need path aliases | You need consistent build artifacts |
Node explicitly states tsconfig.json is ignored and tsconfig-dependent features are intentionally unsupported.
Full TypeScript support: the tsx approach
Node's docs explicitly recommend using a third-party package for full support. The most popular choice is tsx:
Install
npm install --save-dev tsx
Run
npx tsx src/index.ts
# Or:
node --import=tsx src/index.ts
Practical recipes (copy/paste)
Recipe A: "Scripts-only TS" (type stripping style)
Best for: build scripts, tooling, small CLIs
// package.json
{
"type": "module",
"scripts": {
"dev": "node src/index.ts",
"dev:transform": "node --experimental-transform-types src/index.ts",
"typecheck": "tsc --noEmit"
}
}
Recipe B: "App TS" (tsx style)
Best for: apps/services needing real TS features
// package.json
{
"type": "module",
"scripts": {
"dev": "tsx src/index.ts",
"typecheck": "tsc --noEmit",
"test": "node --test"
}
}
- Node's built-in TS is type stripping, not full compilation
- tsconfig.json is intentionally ignored
- Enums and parameter properties need --experimental-transform-types
- Use tsx for full TypeScript support in production apps
- Pick the simplest path that keeps DX + debugging healthy