Node.js runs TypeScript natively in 2026: drop ts-node and your build step

Node.js v22.18 runs TypeScript with no build step and v24 makes it default. How type stripping works, its limits, and what you can drop.

Read time
10 min
Word count
1.3K
Sections
10
FAQs
8
Share
Developer monitor showing code and a glowing terminal at night
Node.js strips TypeScript types and runs the code with no build step.
On this page · 10 sections
  1. What type stripping actually does
  2. The version timeline, so you know what your runtime supports
  3. What breaks, and how to handle it
  4. The tsconfig that keeps your editor and runtime in agreement
  5. The one caveat that decides everything: Node does not type-check
  6. What you can drop, and what you keep
  7. Why this matters beyond convenience
  8. FAQ
  9. How eCorpIT can help
  10. References

Summary. As of 2026 you can hand a .ts file straight to Node.js and it runs, no ts-node, no tsx, no transpile step. The feature is called type stripping, and it arrived in stages: Node.js v22 added an --experimental-strip-types flag, v22.18.0 ran erasable TypeScript with no flag at all, v23.6 turned execution on by default, and v24, the current long-term-support line, ships it on by default. Under the hood Node strips the types with a module named amaro, a thin wrapper around the SWC engine, and replaces each removed annotation with whitespace so line numbers stay identical. The payoff is concrete: fewer dependencies, faster startup, and shorter CI runs, which matter when GitHub Actions bills Linux runners at $0.006 per minute in 2026 after a 40% cut on 1 January, on top of a 2,000-minute monthly free tier. One caveat decides whether this works for you: Node runs your TypeScript, but it does not type-check it.

This guide covers what type stripping does, the syntax it cannot handle, the tsconfig that keeps your editor honest, and exactly which tools you can retire versus keep. It is written for backend and full-stack developers deciding whether to strip the build step out of a real service in 2026.

What type stripping actually does

Type stripping is narrow by design. When Node loads a .ts, .mts, or .cts file, the amaro module removes erasable syntax, meaning type annotations, interfaces, type aliases, and import type statements, then executes the JavaScript left behind. It does not rewrite your code into something else. Because removed types are swapped for whitespace rather than deleted, the byte offsets of your real code do not move, so stack traces and debugger breakpoints land on the correct lines without a source map.

The engine doing the removal is SWC, wrapped by amaro so it can be updated independently of the Node runtime. Marco Ippolito, a member of the Node.js Technical Steering Committee who led the work, explained the naming on his blog with typical honesty: "Amaro means bitter in Italian because the whole thing was a bit bitter." The result, though, is clean. Running a script now looks like this:


            node app.ts
          

No wrapper, no loader flag on a current LTS. For a small service or a script, that removes an entire category of tooling and configuration.

The version timeline, so you know what your runtime supports

The behavior depends on your Node version, and the defaults changed quickly through 2024 and 2025. The table below is the practical summary.

Node.js version TypeScript execution Flag needed
v22.0 to v22.17 Erasable syntax only --experimental-strip-types
v22.18.0+ Erasable syntax runs unflagged None
v23.6 Enabled by default None
v24 (LTS, 2026) Default type stripping None
v24+ with --experimental-transform-types Adds enums, namespaces One flag

If you are on the current LTS, plain node file.ts works. If you are pinned to an older v22, add the flag. The official Node.js guide to running TypeScript natively documents each step, and community write-ups such as Node.js 24 ships native TypeScript track how the defaults moved.

What breaks, and how to handle it

Type stripping only removes syntax that can be erased without changing runtime behavior. Anything that needs Node to generate extra JavaScript is out of scope for stripping alone. In practice that means a specific list of TypeScript features will fail or need a flag.

TypeScript syntax Runs under type stripping? What to do
Type annotations Yes Nothing
Interfaces and type aliases Yes Nothing
import type Yes Nothing
Enums No Use --experimental-transform-types or a union of literals
Parameter properties No Assign fields in the constructor body
Namespaces with runtime values No Use ES modules instead
Decorators No Compile with tsc or SWC; they are still TC39 Stage 3
JSX No Use a bundler or loader for the front end

Decorators are the sharpest edge. Because decorators remain a TC39 Stage 3 proposal, Node does not transform them and does not polyfill them, so a decorated class throws a parser error. Frameworks that lean on decorators, such as some dependency-injection setups, are not ready for pure stripping yet. For those, either keep a compile step or turn on --experimental-transform-types, which handles enums, namespaces, and parameter properties at the cost of leaving the "just erase" fast path.

The tsconfig that keeps your editor and runtime in agreement

The risk with type stripping is a split brain: your editor accepts code that Node will refuse to run. TypeScript 5.8, shipped in early 2025, closed that gap with a compiler option. The `erasableSyntaxOnly` flag makes tsc report an error for any construct that pure erasure cannot handle, so your editor flags an enum or a parameter property before you ever run the file. Pair it with the import options that match Node's resolver.


            {
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "allowImportingTsExtensions": true,
    "rewriteRelativeImportExtensions": true,
    "verbatimModuleSyntax": true,
    "erasableSyntaxOnly": true,
    "noEmit": true
  }
}
          

This is the setup that makes the workflow safe. Your editor and CI use tsc to validate types and to reject non-erasable syntax, while Node runs the files directly. For a wider view of how the TypeScript toolchain is shifting, our look at the Next.js 16.3 and TypeScript 7 toolchain covers the native-speed compilers arriving alongside this change.

The one caveat that decides everything: Node does not type-check

This is the point to internalize before you delete anything. Type stripping deletes your types and runs the code, so it performs zero type checking at runtime. A genuine type error will not stop the process; it will simply run until the bad value causes a normal JavaScript failure, if it causes one at all. Native execution replaces the transpile step, not the type checker.

So the type checker stays in your workflow, it just moves out of the run path:


            tsc --noEmit
          

Run that in your editor via the language server and in CI as a gate. The mental model is a clean split. Node runs the code fast with no build; tsc validates the code separately. Teams that forget the second half ship type-unsafe code with a false sense of safety, which is worse than the old build step they removed.

What you can drop, and what you keep

Here is the honest accounting for a 2026 backend project. Some tools genuinely leave your dependency list; others just change shape.

Task Old tool 2026 native option
Run a .ts file ts-node or tsx node file.ts
Type-check tsc Still tsc, as tsc --noEmit
Run tests Jest node --test with node:test
Run package scripts npm run node --run
Bundle for browsers esbuild or Vite Still needed for the front end

The test runner deserves a note. The built-in node:test module has been in Node core since version 20 and ships with the runtime, so it adds no dependency. One team that replaced Jest with node:test across 12 services reported large speedups, and a simple test needs nothing extra:


            import { test } from "node:test";
import assert from "node:assert/strict";

test("adds numbers", () => {
  assert.equal(1 + 1, 2);
});
          

That said, node:test still lacks some of the polish of Vitest and Jest, including mature snapshot testing and watch-mode ergonomics, so large suites may keep a dedicated runner. As one long-time Node developer put it, you might not need Jest, which is different from never needing it.

Why this matters beyond convenience

Removing the build step is not only about developer comfort. Fewer moving parts means fewer dependency upgrades, fewer transpiler-versus-runtime mismatches, and shorter feedback loops. It also trims CI. With GitHub Actions charging $0.006 per Linux minute in 2026 and a 2,000-minute monthly free tier for private repositories, cutting a transpile stage out of every pipeline run compounds across a busy team. For services that already run on ES modules and avoid decorators, the native path is a straightforward win. For projects deep in decorator-heavy frameworks, it is a signal to plan a migration rather than a switch to flip today. If you are modernizing an older codebase, our guide to moving a monolith to microservices pairs well with this shift, since both are about removing accidental complexity.

FAQ

How eCorpIT can help

eCorpIT is a Gurugram-based engineering organization, founded in 2021 and assessed at CMMI Level 5, with senior-led teams that build and modernize Node.js and TypeScript backends. We help teams simplify toolchains, cut CI time, and migrate decorator-heavy or legacy services toward the native TypeScript path without breaking type safety. If you want a pragmatic review of your build pipeline and test setup, talk to our engineers about a toolchain audit.

References

  1. Node.js, Running TypeScript natively
  1. Node.js API docs, Modules: TypeScript
  1. Marco Ippolito, Everything you need to know about Node.js type stripping
  1. DEV, Node.js 24 ships native TypeScript: the end of build steps?
  1. oida.dev, TypeScript's erasableSyntaxOnly flag
  1. TypeScript, TSConfig option erasableSyntaxOnly
  1. Steve Kinney, Type stripping in Node.js
  1. Pawel Grzybek, You might not need Jest
  1. Node.js, Using the test runner
  1. DEV, We replaced Jest with node:test in 12 services
  1. GitHub Docs, Actions runner pricing
  1. SitePoint, TypeScript 5.8 erasable syntax and running TS in Node.js

_Last updated: 12 July 2026._

Frequently asked

Quick answers.

01 Can Node.js run TypeScript without a build step now?
Yes. Since Node.js v22.18.0, you can run a .ts file directly with no flag, as long as it uses only erasable TypeScript syntax. Node v23.6 made this default, and v24, the current LTS in 2026, ships type stripping on by default. No ts-node or transpile step is required for that case.
02 What is type stripping?
Type stripping removes TypeScript-only syntax, such as type annotations, interfaces, and type aliases, then runs the JavaScript that remains. Node.js does this through the amaro module, which wraps the SWC engine. It replaces the removed types with whitespace so line numbers stay identical and stack traces still point to the right place.
03 What TypeScript features do not work?
Anything that needs runtime code generation is unsupported by stripping alone: enums, parameter properties, namespaces with runtime values, and decorators, which are still a TC39 Stage 3 proposal. JSX is also not handled. For these, use the --experimental-transform-types flag or a real compiler like tsc or SWC.
04 Does Node.js type-check my TypeScript?
No, and this is the most important caveat. Type stripping deletes types and runs the code without checking them, so a type error will not stop your program at runtime. You still need tsc, usually as tsc --noEmit, in your editor and CI to catch type errors. Node runs the code; tsc validates it.
05 What is the erasableSyntaxOnly flag?
erasableSyntaxOnly is a TypeScript compiler option shipped in version 5.8 in early 2025. It makes tsc report an error for any syntax that pure type erasure cannot handle, such as enums and parameter properties. Turn it on so your editor flags code that Node's stripper would reject before you run it.
06 Can I replace Jest with the built-in test runner?
Sometimes. The node:test runner has been in Node core since version 20 and needs no dependencies, and teams report tests running far faster than under Jest. It still lacks some conveniences like polished snapshot testing and watch-mode DX, so for large suites Vitest or Jest may fit better. For libraries and small services, node:test is enough.
07 What tsconfig should I use for native TypeScript?
A Node-native setup usually sets target to esnext, module to nodenext, and turns on allowImportingTsExtensions, rewriteRelativeImportExtensions, verbatimModuleSyntax, and erasableSyntaxOnly. That combination lets you import .ts files by path, keeps imports explicit, and makes tsc reject anything Node's stripper cannot run, so your editor and runtime agree.
08 Does this remove the need for a bundler?
For server code, often yes: you can run and test TypeScript with just Node. For browser code you still need a bundler, because the browser cannot run raw TypeScript or resolve Node modules. Think of native TypeScript as removing the server build step, not every build tool in your stack.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.