Run TypeScript Directly in Node.js: Type Stripping and the One Big Catch
Node.js 24 runs TypeScript directly, no ts-node and no build step, via type stripping. The catch is it erases types rather than checking them. Here is the safe workflow.

You can run a TypeScript file with node app.ts and nothing else. No ts-node, no tsx, no build step, no tsconfig. Node.js 24, the current LTS, ships native TypeScript support switched on by default, and it is stable now, not experimental. It is a genuine quality-of-life win. It is also easy to misunderstand, because of what it does not do.
Key takeaways
- On Node.js 24 LTS,
node app.tsruns directly, nots-node, no build step, no flag.- It works by stripping type annotations before V8 runs the code, not by compiling.
- The catch: stripping does not type-check. Keep
tsc --noEmitin CI to catch type errors.
How it works: stripping, not compiling
Node does not compile your TypeScript. It strips it. Before V8 ever sees your code, Node uses Amaro (a thin wrapper around SWC's WebAssembly TypeScript parser) to remove the type annotations, then runs the plain JavaScript that is left. A nice detail: the stripped syntax is replaced with whitespace rather than deleted, so line and column numbers in stack traces still line up with your source.
The feature arrived in stages. Node 22 introduced it behind --experimental-strip-types, Node 23 unflagged it, and Node 24 makes it the default for any .ts file, stable, and available in the Node 22 LTS line as well (from 22.18). On Node 24 you need no flag at all. The official behavior is documented in the Node.js TypeScript modules docs.
Try it yourself
On Node 24 there is no setup. Save this as greet.ts:
function greet(name: string): string { return `Hello, ${name}!`;}console.log(greet("Node 24"));Run it directly, no tsc, no ts-node, no config:
$ node --versionv24.20.0$ node greet.tsHello, Node 24!Now the part that surprises people. Save broken.ts, where port is typed as a number but assigned a string:
const port: number = "3000";console.log(`Listening on port ${port}`);Node runs it anyway, because it strips the : number annotation instead of checking it:
$ node broken.tsListening on port 3000The compiler would have stopped you:
$ npx tsc --noEmit broken.tsbroken.ts(3,7): error TS2322: Type 'string' is not assignable to type 'number'.That gap between "it runs" and "it is correct" is the whole story.
The one big catch: it does not type-check
This is the part to internalize. Stripping is whitespace-only, and Node never validates your types. node app.ts will happily run code that tsc would reject. Native execution replaces your build step, not your type checker.
The practical consequence: keep running tsc --noEmit in CI. That is where type errors get caught now. Type stripping speeds up running and iterating; it does not remove the need to type-check before you ship.
What is not supported
Because it only strips, a few things do not work out of the box:
- Enums and namespaces need real code generation, not stripping. Node had an
--experimental-transform-typesflag for them, but that flag is being removed, so the pragmatic move is to avoid enums and namespaces in files you run directly, or precompile those. tsconfig.jsonis ignored. Path aliases and anything else you configure there do not apply.- No JSX.
.tsxfiles are not handled.
When to use it
Native stripping shines for scripts, tooling, tests, and server entry points where a build step was pure friction. Cold starts get dramatically faster too: on a real Express server, moving from ts-node to native stripping took cold start from about 1.4 seconds to roughly 200 milliseconds, about 7 to 9 times faster. For a production build where you want declaration files, bundling, and full type checking, you still reach for tsc or your bundler.
Pair it with the compiler, not instead of it. Node runs your TypeScript, and tsc --noEmit still tells you whether it is correct. On the compiler side, the checker itself just got much faster: see TypeScript 7.0's Go rewrite.
Join the discussion on Run TypeScript Directly in Node.js: Type Stripping and the One Big Catch
Likes, comments, and replies are available for authenticated readers with verified email addresses.
Comments (0)
Loading discussion...Related articles

The State of AI-Generated Code in 2026: Adoption Soars, Security Lags
AI now generates much of the world's new code and adoption is near-universal, but roughly 44% of AI-generated code carries a security vulnerability, and the EU AI Act's biggest deadline just landed.

TypeScript 7.0's Go Compiler: What Changed and How to Adopt It
TypeScript 7.0 is a native Go port of the compiler, 8 to 12 times faster with no new syntax. Here is what changes, the tooling caveats, and how to roll it out in stages.