Node.js 26 release notes highlighting the removal of the experimental-transform-types flag and its impact on TypeScript enum support.
Zamir Khotov May 7, 2026 Frameworks & JavaScript

Node.js 26 Quietly Killed Your TypeScript Enums

📧 Subscribe to JavaScript Insights

Get the latest JavaScript tutorials, career tips, and industry insights delivered to your inbox weekly.

A developer messaged me on Tuesday morning asking why his deploy was broken. He had just upgraded a small internal tool to Node.js 26 the same day the release dropped. Local tests passed. CI passed. The container built. Then the service refused to start in production with an error nobody on his team had ever seen before.

He was running TypeScript directly through Node, the way the Node team had been promoting for the past 18 months as the future of the runtime. No build step, no tsc, no esbuild, no tsx. Just node app.ts and let the runtime handle the rest. It worked beautifully on Node 23 and 24 with one experimental flag. It worked on Node 25 with the same flag. On Node 26 the flag is gone.

His app was full of TypeScript enums. The kind every backend developer writes without thinking. Status enums, role enums, error code enums. The kind of code that compiles cleanly with tsc and runs cleanly with ts-node and breaks immediately when Node 26 tries to load it without a transformer.

This is the story of how the Node.js team quietly killed one of the most ambitious TypeScript integration efforts in the runtime's history, and why most teams will not realize it until something fails at 3am.

What Actually Happened in the Node.js 26 Release

The Node.js 26 release on May 5 had three headline features. Temporal API enabled by default. V8 updated to 14.6 with new methods like Map.prototype.getOrInsert. Undici bumped to 8.0 with tighter HTTP client behavior. The release blog covered these in detail. Tech press covered them in detail. The Twitter discussions covered them in detail.

Almost nobody covered the third item buried in the deprecations list. The flag --experimental-transform-types was removed. Not deprecated. Not warned about. Removed.

If you have been following Node's TypeScript story for the past two years, you know why this matters. If you have not, here is the short version. Node.js 22.6 introduced --experimental-strip-types in August 2024, which let you run TypeScript files by stripping the type annotations and treating the rest as plain JavaScript. The catch was that some TypeScript features cannot be stripped because they generate runtime code. Enums are the obvious example. Namespaces and parameter properties are the others.

To handle these features Node added a second flag a month later called --experimental-transform-types. This one ran a real transformation step that produced executable JavaScript from TypeScript-only syntax. With this flag, Node could finally execute the TypeScript code most teams write in production, including enums.

For about 20 months, this was the path forward. Run your TypeScript directly through Node. Skip the build step. Use experimental flags now, watch them stabilize over time, eventually have full TypeScript support natively in the runtime. The Node team blogged about it. Conference talks covered it. Several open source projects started experimenting with shipping TypeScript directly without a build pipeline.

Node 26 ended that path. The strip-types behavior is still there and now enabled by default. But the transform-types capability is gone, with no replacement. If your code uses enums and you depended on Node executing it directly, your code does not run anymore.

Why This Breaks More Code Than the Node Team Estimated

The Node.js TSC will tell you this affects a small number of users. Native TypeScript execution was experimental. Production deployments rarely depended on it. The breaking change is contained to people who knowingly opted into experimental behavior.

I think this underestimates the scope. Here is what I observe from running a job board and talking to developers daily.

A lot of internal tools and side projects shipped with --experimental-transform-types because it was simpler than configuring tsc. Small CLI scripts, internal automation, prototype servers, cron jobs, deployment helpers. Code that nobody talks about at conferences because it is boring and works. Code that was written once and forgotten. The kind of code that does not have CI coverage of the upgrade path.

A lot of tutorials and YouTube videos in 2025 told developers to just use --experimental-transform-types as a shortcut for getting TypeScript running. Those tutorials are still online. Developers who learned Node in the last 18 months, as TypeScript became the default for backend work, may genuinely not know there is a difference between the two flags or that one was experimental. They just know "node runs my TypeScript".

Companies running on managed Node platforms like Vercel functions, AWS Lambda with Node runtimes, and various PaaS providers may have automatic Node version upgrades configured. When those platforms move to Node 26 LTS in October, code that has been working for months will break for reasons that have nothing to do with what the team last touched. The post-mortem will say "we upgraded a runtime version", not "we depended on an experimental TypeScript feature".

This is the part that turns a "documented breaking change" into the 3am wake-up call every backend engineer dreads. Most teams do not know which experimental flags their deployment depends on, because the flags were added by whoever set up the project two years ago. They left. The flag is in the Dockerfile. Nobody reads the Dockerfile until something breaks.

What CI Will Not Catch and Production Will

CI environments run the version of Node you pin in your package.json or your CI config. Most teams pin to a specific major version like 20 or 22. CI will keep passing happily on Node 22 even when production has moved to 26. The flag still exists in 22, 23, 24, 25. The flag does not exist in 26.

The first signal you get is when a production environment that auto-upgrades hits Node 26. The error you see depends on what your code does. If your enum is at module scope and gets touched on cold start, the service fails to boot. If your enum is in a code path that only runs under specific conditions, you have a latent bug that triggers when a customer hits the wrong endpoint at the wrong time.

The error message itself is not as helpful as you would want. Node throws ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX with a line number. Most engineers reading that for the first time will assume it is a syntax error in their code, not a runtime configuration mismatch. They will look at the line, see a perfectly valid TypeScript enum, and start questioning their understanding of TypeScript.

If you are a developer who has been told for two years that Node runs TypeScript natively, this error makes no sense. Your code is TypeScript. You are running it on Node. The error says TypeScript is unsupported. The mental model breaks before the bug becomes diagnosable.

The fix is not hard once you know what to look for. The discovery is hard.

The Migration Path That Actually Works

You have three real options if your code is affected, and one fake one that I see people consider but should not.

The first real option is to add a build step. This is the boring answer. Run tsc or swc or esbuild before deployment, ship the compiled JavaScript, run that with Node. Yes, you lose the elegance of running .ts directly. Yes, it adds tooling. It also takes about 20 minutes to set up and works on every Node version including older ones. For production code, this should have always been the answer.

The second real option is to use a third-party TypeScript-aware runtime. tsx, ts-node, Deno, or Bun. These tools handle the full TypeScript syntax including enums and continue to work fine. If your project is small enough that adding a build step feels like overkill, switching to tsx for development and Node for production with a build step is a reasonable middle ground.

The third real option is to refactor your enums into const objects. This is what the TypeScript team and the Node team are both quietly recommending. The pattern looks like this.

const Status = {
  ACTIVE: 'active',
  PENDING: 'pending',
  ARCHIVED: 'archived',
} as const;

type Status = (typeof Status)[keyof typeof Status];

This compiles to nothing at runtime. It works in strip-mode TypeScript. It is what TypeScript 5.8's new --erasableSyntaxOnly flag will validate. Functionally it gives you the same type safety as a string enum with slightly different ergonomics. For new code this pattern is now the right choice. For existing code, refactoring 200 enum declarations across a codebase is real work that nobody scheduled.

The fake option is to wait for the Node team to bring back the flag. They will not. The reason --experimental-transform-types was removed is that maintaining it added complexity to the runtime that the TSC decided was not worth carrying. The signal is clear. Native runtime transformation of TypeScript-specific syntax is not part of Node's roadmap. The only TypeScript syntax Node will execute directly is the syntax that erases cleanly, and enums do not.

The Bigger Story Nobody Is Telling

Here is the part of this that bothers me. Native TypeScript support in Node was sold for two years as a path forward. Tutorials promoted it. Conference speakers praised it. The Node team itself promoted it as evidence that the runtime was modernizing.

Now half of that path is gone, and the messaging has shifted to "you should not have used the experimental flag in production anyway". Which is technically correct and politically convenient. The flag was experimental. Anyone reading the documentation knew that. But the broader narrative of "Node runs TypeScript now" was always more confident than the actual feature warranted, and a lot of developers absorbed that narrative without reading the fine print.

This is the kind of thing that erodes trust in a runtime. Not the breaking change itself. Breaking changes happen in major versions. The erosion comes from the gap between marketing language and engineering reality. When the team says "TypeScript support is here" and 18 months later removes the part that made it actually useful, developers learn to discount the next big announcement.

I think Node will recover from this. Strip-mode TypeScript is genuinely useful. The Temporal API rollout in this same release is going to do a lot of good. V8 14.6 has real performance wins. The runtime is in better shape than it has been in years.

But the TypeScript story specifically just got a lot more confusing for new developers. If you are learning Node in 2026, the right answer to "how do I run TypeScript on Node" depends on whether you are using enums, what version you are on, what flags are available, and whether you want to learn this all yourself or just use Bun. The simple narrative the Node team was telling for two years is over.

What This Means If You Are Hiring or Job Hunting

I run a JavaScript job board, so I read job postings every day. I have watched the Node version requirements in postings shift over the past year. Most senior backend roles now ask for Node 20 LTS minimum. Some ask for Node 22. A few are starting to mention Node 24. Within six months, Node 26 will be standard for new postings, especially in startups that follow the latest releases closely.

If you are a developer interviewing in the next year, expect questions about how you handle TypeScript in production. Two years ago the answer was tsc, ts-node, or your bundler. Last year it was "Node can do it natively now". This year the right answer is going to be more nuanced. You should be able to explain when to use a build step, when native strip-mode is enough, and what happens when your team needs enums. Saying "I just run node app.ts" is no longer the modern answer. It is the answer of someone who has not read the release notes since 2024.

If you are a hiring manager, this is a small but useful signal in interviews. Asking a backend candidate "how do you run TypeScript on Node these days" gets you more information about how engaged they are with the ecosystem than most technical questions do. Engaged engineers know the story changed. Disengaged ones are still reciting last year's recipe.

What I Would Do This Week

If I had a Node project with TypeScript enums in production right now, here is the order I would handle this in.

Check what flag your deployment is using. If you have --experimental-transform-types anywhere in a Dockerfile, a process manager config, a CI script, or a deployment YAML, you are at risk when Node 26 lands. Find every occurrence and document it.

Check what Node version your auto-upgrade behavior is targeting. If you use a managed platform that picks "current LTS", you will hit Node 26 in October when it transitions to LTS. That gives you five months. If you use "current major" or have automatic upgrades to current releases, you may already be on Node 26. Check now.

Add a build step if you do not already have one. tsc with a minimal tsconfig.json is fine. esbuild is faster and almost as configurable. Either gets you off the experimental path and onto something stable. This is one afternoon of work for most projects.

Audit your enum usage. If you have enums and want to keep them, the build step solves the problem. If you wanted an excuse to switch to const objects, this is the excuse. The tooling around as const objects has gotten much better in TypeScript 5.8 and the migration is mechanical.

Tell your team. The most expensive version of this bug is the one that catches a senior engineer at midnight on a Sunday during a deploy because nobody mentioned it in the team channel. Ten minutes in standup costs nothing. The on-call shift it prevents could save someone's weekend.

The Lesson Beyond Node 26

I have been watching JavaScript runtimes for a long time, and the pattern I see in this story is one that repeats. A runtime announces ambitious feature support. Tutorials and tooling rush to use the new capability. The runtime team learns the implementation is harder to maintain than expected. The feature gets quietly walked back. Developers who built on the announcement end up holding the bag.

This is not a Node-specific failure. Deno walked back its bundler. Bun has shifted some of its early ambitions around npm compatibility. Browsers have introduced and deprecated APIs faster than developers can adopt them. The lesson is not "trust nothing". The lesson is that experimental flags exist for a reason, and if you depend on one in production, you accept the risk that it goes away.

The senior engineers I respect have all internalized this. They use experimental features in side projects and prototypes. They keep production on the boring stable path. When the experimental feature works out and stabilizes, they migrate. When it gets cut, they shrug and continue.

The Node 26 enum story is going to teach a generation of mid-level developers that lesson the painful way. Read your release notes. Audit your flags. Do not put experimental on the critical path. The runtime will keep moving, and your production code needs to keep working through the moves.

Related articles

career 4 months ago

Python Overtook JavaScript on GitHub: Why This Is Actually Good News for JS Developers

GitHub's Octoverse 2024 and 2025 reports document a historic shift that JavaScript developers need to understand correctly. Python briefly overtook JavaScript in late 2024 after a decade of JS dominance, driven by a 59% surge in AI and data science projects. But here's what the headlines miss: by August 2025, TypeScript, JavaScript's typed superset, reclaimed the number one position, surpassing both Python and JavaScript. This isn't JavaScript losing ground. This is JavaScript evolving and fragmenting its ecosystem in ways that make simple language rankings misleading. JavaScript still dominates code pushes, npm grew 15% year-over-year to over 2 million packages, and the combined JavaScript plus TypeScript ecosystem accounts for more total development activity than any other language family.

John Smith Read more
Bun vs Deno vs Node.js in 2026 and Why Your Runtime Choice Actually Matters Now
frameworks 3 months ago

Bun vs Deno vs Node.js in 2026 and Why Your Runtime Choice Actually Matters Now

The JavaScript runtime wars have reached a turning point. For over fifteen years, Node.js stood alone as the undisputed king of server side JavaScript. Developers never questioned their runtime choice because there was no choice to make. You wanted to run JavaScript outside the browser, you used Node.js. Period.

John Smith Read more
JavaScript Application Architecture in 2026 and Why System Design Is the One Skill AI Cannot Automate
infrastructure 2 months ago

JavaScript Application Architecture in 2026 and Why System Design Is the One Skill AI Cannot Automate

Every week, another AI tool ships that can write React components, generate API routes, and scaffold entire applications in seconds. Claude builds workflows. Copilot autocompletes your functions. Cursor rewrites your files. And yet, the developers earning $250K+ are not worried. Not even a little.

John Smith Read more