Node.js 25: Native Stripping of TypeScript Types
Node.js 25 dropped yesterday. V8 14.1, faster JSON.stringify for large payloads, native Uint8Array base64/hex conversion. Solid release. But honestly, the headline for me is the TypeScript type stripping story finally reaching its conclusion.
Type stripping—Node.js natively running .ts files by ripping out type annotations at parse time—shipped unflagged in Node.js 23.6 but still carried the “experimental” label. With 25.2 (landing shortly after this initial release), that label goes away. Stable. No flags, no warnings. You run node script.ts and it just works.
I’ve been waiting for this since the feature was first proposed.
What “Type Stripping” Actually Means #
Worth being precise here, because I’ve seen people get confused. Node.js doesn’t compile TypeScript. It doesn’t type-check your code. It strips. Type annotations, interfaces, type aliases, generics; anything that exists purely at the type level gets removed. What remains is valid JavaScript that V8 runs normally.
function greet(name: string): string {
return `Hello, ${name}`;
}Becomes, effectively:
function greet(name ) {
return `Hello, ${name}`;
}(The spaces preserve source map alignment. The real implementation handles this more carefully, but that’s the right mental model.)
There’s a deliberate limitation: type stripping only handles syntax you can remove without understanding program semantics. Enums and namespaces require actual code transformation, not just deletion, so they aren’t supported under basic stripping. You’d reach for --experimental-transform-types if you need those.
In practice? Not a real constraint for most codebases. The TypeScript community moved away from enums (favoring as const objects) and namespaces (favoring ES modules) years ago. If you write modern TypeScript, stripping handles it.
Why I Care About This #
I’ll be direct: I’ve wasted more hours than I want to admit setting up compilation steps for throwaway scripts. You know the pattern. You need a quick CLI tool or automation script, you reach for TypeScript because you want the type safety, and then you spend ten minutes configuring tsconfig.json and picking between ts-node, tsx, or swc before you write a single line of actual logic.
npx ts-node script.ts works but adds noticeable startup latency (ts-node bootstraps the full TypeScript compiler). npx tsx script.ts is faster since it uses esbuild under the hood, but it’s still an external dependency you’re pulling in. With node script.ts, the overhead basically vanishes. For scripting and quick tools, that gap between “I’ll just use TypeScript” and “ugh, let me use plain JS, it’s less hassle” disappears.
Development workflows get simpler too. The compile-then-run cycle adds friction; small per iteration but cumulative over a day. Hot reloading tools like nodemon help, though they’re still orchestrating a build step underneath. node --watch script.ts gives you file-watching and re-execution with no build pipeline in between.
And then there’s the ecosystem angle. Deno and Bun have run TypeScript natively for years; Node.js was the last runtime standing without it. Now all three handle .ts out of the box. Library authors can ship TypeScript examples that actually run everywhere (something that was surprisingly annoying before). Documentation gets simpler. One fewer caveat to explain.
The Rest of Node.js 25 #
Quick hits on the other changes.
V8 14.1 improves JSON.stringify performance for large payloads. If you’re serializing big API responses or log entries, free speedup. No code changes required.
Native Uint8Array base64/hex encoding and decoding. Previously you’d lean on Buffer.from(data, 'base64') or grab a library. Now Uint8Array handles it natively, which matters for workers and cross-runtime code where Buffer isn’t available.
The permission model picked up --allow-net for network access control, following --allow-fs-read and --allow-fs-write. You can restrict which network addresses a script can reach. Handy for sandboxing scripts that shouldn’t phone home.
Web Storage enabled by default. ErrorEvent now a global. SlowBuffer (deprecated since Node.js 6, so long overdue) finally removed. Standard housekeeping that continues aligning Node.js with web platform APIs.
One thing to flag: Node.js 25 is odd-numbered, so no LTS. For production stability, wait for Node.js 24 LTS “Krypton” later this month. But if you want stable type stripping and the V8 improvements, 25 is where everything lands together.
The Arc #
The TypeScript-in-Node story played out over roughly two years. Experimental flag in Node.js 22. Unflagged default in 23.6. Stable in 25.2. That’s a pretty fast graduation for a feature this significant.
What makes it matter isn’t that it enables something impossible before (ts-node existed, tsx existed). It removes the friction that made TypeScript just annoying enough to skip for quick tasks. I’ve caught myself defaulting to plain .js for one-off scripts purely because the setup tax wasn’t worth it. That calculus changed yesterday.