
Node Enum Not Supported? Fix It in Node 24
Skilldham
Engineering deep-dives for developers who want real understanding.
You upgraded to Node 24. You ran node app.ts with no build step. It just worked.
Then you added an enum.
Now the terminal throws a wall of red. TypeScript enum is not supported in strip-only mode. You did not change the enum. You did not touch your config. It worked an hour ago.
You start Googling and land three tabs deep in GitHub issues from 2025.
Here is the truth. Node 24 is not broken. Your enum is doing exactly what enums always do. The new runtime just cannot handle it. Let me show you why, and the three ways to fix it. If TypeScript build errors are a regular pain for you, our guide on common TypeScript build errors and fixes covers the wider set.
Quick Answer
If you see node enum not supported, it is because Node 24 runs node app.ts using type stripping. Stripping only deletes type annotations. An enum is not just a type - it compiles into a real runtime object. Stripping cannot build that object, so Node throws. Fix it three ways: replace the enum with an as const object, run with --experimental-transform-types, or add a tsc build step.
Why Node Enum Not Supported Shows Up in Node 24
Node 24 can run TypeScript files directly. No tsc. No build folder. You type node app.ts and it runs.
It does this with a trick called type stripping. Node reads your file. It deletes every type annotation. It runs the plain JavaScript that is left.
Type Stripping Only Removes Types
Stripping is a delete operation. It does not rewrite code. It does not generate anything new.
Look at a normal function.
typescript
// Source: TypeScript with type annotations
function sum(a: number, b: number): number {
return a + b;
}typescript
// After stripping: types are just erased, code stays
function sum(a, b) {
return a + b;
}That works because the types were decoration. Remove them and valid JavaScript remains.
Enums Generate Real Runtime Code
An enum is different. It is not decoration. The TypeScript compiler turns an enum into a live JavaScript object.
typescript
// Wrong: this enum needs runtime code that stripping cannot create
export enum Status {
Active = "ACTIVE",
Inactive = "INACTIVE",
Pending = "PENDING",
}
console.log(Status.Active); // dies under node app.tsStripping deletes types. It does not build objects. There is no type to delete here - there is real code to generate. So Node gives up and throws.
typescript
// Correct: a plain object needs no transformation at all
export const Status = {
Active: "ACTIVE",
Inactive: "INACTIVE",
Pending: "PENDING",
} as const;
console.log(Status.Active); // runs fine with node app.tsThe fix works because the object is already JavaScript. Nothing needs to be generated. Node just runs it.

The Exact Error You Are Seeing
Most posts paraphrase the error. Here is the real one, copied straight from the terminal.
bash
node app.ts
node:internal/modules/typescript:52
throw new ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX(error);
^
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only modeWhat the Error Actually Means
"Strip-only mode" is the key phrase. Node ran in its default mode. That mode strips and nothing else.
The error code matters too. In Node 24 it reads ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX. Earlier builds used ERR_INVALID_TYPESCRIPT_SYNTAX. If you see the older code, you are on an older runtime.
Why It Worked Before Node 23.6
This is a version story. Before Node 23.6, stripping was behind a flag. You had to opt in.
Node 23.6.0 unflagged --experimental-strip-types and turned it on by default. Node 22.18 backported the same default. Node 24 ships it on out of the box.
So nothing in your code changed. The runtime changed under it. This is the same trap behind many "works locally but breaks in production" bugs - a version gap you did not see.
Fix 1: Replace the Enum With a const Object
This is the fix I reach for first. It removes the problem instead of working around it.
You already saw the pattern above. Here it is with full type safety added.
typescript
// Wrong: enum that cannot survive stripping
export enum Role {
Admin = "ADMIN",
Editor = "EDITOR",
Viewer = "VIEWER",
}typescript
// Correct: const object plus a derived type
export const Role = {
Admin: "ADMIN",
Editor: "EDITOR",
Viewer: "VIEWER",
} as const;
// This line gives you the union type "ADMIN" | "EDITOR" | "VIEWER"
export type Role = (typeof Role)[keyof typeof Role];
function setRole(role: Role) {
console.log(role);
}
setRole(Role.Admin); // type-checked, and runs with node app.tsThe as const Pattern
as const freezes the object. Its values become exact string literals, not just string. That gives you the same narrow typing an enum gave you.
The keyof typeof line builds a union from those values. You get autocompletion and compile-time checks. You lose nothing an enum offered for most use cases.
Why This Is the Future-Proof Fix
This code is plain JavaScript. It runs in Node with no flag. It runs in the browser. It runs in any bundler.
You stop depending on a compiler step that may or may not be there. That is why the wider ecosystem now leans toward as const over enums.
Fix 2: Run With --experimental-transform-types
Sometimes you cannot rewrite the enum. Maybe it lives in a shared package. Maybe a teammate owns it. You just want the file to run.
bash
# Wrong: bare run strips only, so the enum throws
node app.ts
# Correct: transform mode compiles enums and namespaces
node --experimental-transform-types app.tsWhen to Use the Flag
Use the flag when the enum is not yours to change. The flag tells Node to do a real transform, not just a strip. It builds the runtime object the enum needs.
The Tradeoff
This is still an experimental flag, per the official Node docs. It can change between releases.
It also turns off source map skipping and does more work per file. For one script that is fine. For a large app, prefer a real build step. You can read the exact behaviour in the Node.js TypeScript docs.
Fix 3: Add a Real Build Step
The runtime stripping feature is for quick runs and small scripts. Real apps still benefit from a compiler.
bash
# Wrong: trusting the runtime with TS-only syntax in a real app
node app.ts
# Correct: compile first, then run plain JavaScript
npx tsc
node dist/app.js
# Or use tsx, which transforms everything including enums
npx tsx app.tsWhen You Actually Need This
Pick a build step when you ship to production. A compiler catches type errors, handles every TS feature, and outputs portable JavaScript.
tsx is the middle ground. It transforms on the fly, so enums work, and you skip a separate build folder during development.
Catching It Early With erasableSyntaxOnly
You do not have to wait for the runtime to fail. TypeScript 5.8 added a flag that flags non-erasable syntax in your editor.
json
// tsconfig.json - red-underline enums and friends as you type
{
"compilerOptions": {
"erasableSyntaxOnly": true
}
}Turn this on and your editor warns you the moment you write an enum that stripping cannot handle. You catch it at edit time, not at 11pm in a terminal.
The Other Syntax That Breaks the Same Way
Enums get the headlines. They are not alone. Three other TypeScript features fail in strip-only mode for the same reason. They all generate runtime code.
typescript
// Wrong: all three throw under node app.ts in strip-only mode
namespace Utils {
export const greet = () => "hi";
}
class Service {
constructor(private readonly db: Database) {} // parameter property
}
import Level = Logger.Level; // import equalstypescript
// Correct: plain JS equivalents that strip cleanly
export const greet = () => "hi";
class Service {
private readonly db: Database;
constructor(db: Database) {
this.db = db;
}
}
import { Level } from "./logger";The rule is simple. If a feature exists only in TypeScript and produces code, stripping cannot handle it. Types vanish cleanly. Code-generating syntax does not.
Key Takeaways
Node enum not supported happens because Node 24 runs node app.ts with type stripping, which deletes types but cannot generate the runtime object an enum needs
The exact error is SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
Nothing in your code changed - Node 23.6 unflagged stripping by default, and Node 24 ships it on
The cleanest fix is an as const object with a keyof typeof derived type, which is plain JavaScript everywhere
Use --experimental-transform-types only for scripts you cannot edit, since it is still experimental
Real apps should keep a tsc or tsx build step instead of leaning on runtime stripping
Turn on erasableSyntaxOnly in tsconfig to catch enums, namespaces, and parameter properties at edit time
FAQs
Why does node app.ts fail with "TypeScript enum is not supported in strip-only mode"?
Node 24 runs your file by stripping type annotations and nothing else. An enum is not a type, it is code that compiles into a runtime object. Stripping cannot build that object, so Node throws the error.
How do I run a TypeScript enum in Node 24?
You have three options. Run with node --experimental-transform-types app.ts, use npx tsx app.ts, or compile first with tsc and run the output JavaScript. The bare node app.ts command will not work with an enum.
Does --experimental-transform-types slow down my app?
It does more work per file than plain stripping because it transforms, not just deletes. For a single script the difference is tiny. For a large codebase a proper build step is faster and more predictable.
Are const enums supported by Node type stripping?
No. A const enum needs the compiler to inline its values at build time. Stripping does no transformation, so const enums also fail. Use an as const object instead.
Why did this work in Node 22 but break in Node 24?
Stripping used to be behind a flag. Node 23.6 turned it on by default and Node 24 ships it that way. Your enum always needed transformation. The default runtime mode changed, so the failure surfaced.
Should I stop using enums in TypeScript?
Not always, but the as const object pattern is more portable and runs anywhere with no build step. Many teams now prefer it for exactly this reason. Reserve enums for codebases that always compile with tsc.
What other TypeScript syntax breaks in strip-only mode?
Namespaces with runtime code, parameter properties in class constructors, and import = equals declarations. They all generate JavaScript, so stripping cannot handle them. Rewrite each as plain JavaScript.
Does tsx or ts-node fix this?
Yes. Both transform your TypeScript rather than only stripping it, so enums and the other code-generating syntax work. tsx is the lighter, faster choice for most projects in 2026.
Conclusion
Node 24 did not break your enum. It changed how it runs your files, and an enum was never safe to strip. Once you see that stripping deletes types while enums generate code, the fix is obvious.
This matters because the same rule covers namespaces, parameter properties, and import =. Learn it once and you stop guessing.
The cleanest path forward is the as const object. It runs everywhere with zero config. If build-time failures are a recurring theme for you, the TypeScript build errors guide tackles the next layer of problems.