# TypeScript Without a Build Step: Native Type Stripping in Node.js

Node.js can now run TypeScript files natively. No ts-node, no tsc, no esbuild. Just node index.ts and you are done. Here is what type stripping actually means, why it matters, and when you still need a proper build step.

Tags: typescript, nodejs, javascript
Published: 2026-03-07 (updated 2026-10-22)


For years, running TypeScript in Node.js meant picking your poison: `ts-node`, `tsx`, `esbuild`, or setting up a full `tsc` pipeline. Every new project started with the same ceremony: install the compiler, configure `tsconfig.json`, wire up your scripts, and hope nothing breaks.

That era is ending. Node.js ships with native TypeScript support via **type stripping**. It was added in v22.6 behind a flag, enabled by default in v23.6 and v22.18, and declared stable in v25.2 and v24.12 (per the Node.js docs). On a current Node.js release you can run `.ts` files directly.

```bash
node index.ts
```

That is it. No flags, no config, no extra dependencies.

**How do you run TypeScript in Node.js without compiling?** Use a version with type stripping enabled (v22.18+, v23.6+ or any v24 and newer) and run `node file.ts`. Node removes the type annotations and executes the JavaScript underneath. It does no type checking, ignores `tsconfig.json`, and does not support syntax that needs code generation, such as `enum`.

---

## What Is Type Stripping?

Type stripping is exactly what it sounds like: Node.js reads your TypeScript file and strips out all the type annotations before executing it. The types are treated as comments: they are never checked, just removed.

```typescript
// What you write
function greet(name: string): string {
  return `Hello, ${name}`;
}

// What Node.js sees
function greet(name) {
  return `Hello, ${name}`;
}
```

The runtime never sees the types. There is no type checking happening here. The types are there for your editor and your `tsc` runs. Node.js just ignores them and executes the JavaScript underneath.

---

## Why This Is a Big Deal

Before this, even simple Node.js scripts in TypeScript required a setup step. If you wanted to write a quick automation script, a CLI tool, or a one-off data migration in TypeScript, you had two options:

1. Set up a full build pipeline (overkill)
2. Use `ts-node` or `tsx` as a dev dependency (an extra tool to manage)

Now the workflow for TypeScript scripts is identical to plain JavaScript scripts:

```bash
# No setup needed
node my-script.ts
```

This is especially impactful for:

- **CLI tools:** ship a single `.ts` file and let users run it directly
- **Scripts and automation:** write TypeScript without the overhead
- **Monorepos:** shared scripts no longer need their own build config
- **Quick prototyping:** spin up a new file and run it instantly

---

## What Still Works

Anything that can be removed without changing the JavaScript works:

- Type annotations, interfaces, and type aliases
- Generics
- `as` casts and `satisfies`
- Optional chaining and nullish coalescing
- `import type` statements

```typescript
interface User {
  id: number;
  name: string;
  role: 'admin' | 'user';
}

async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  return (await res.json()) as User;
}
```

All of the above runs fine with `node fetchUser.ts`.

---

## What Does Not Work

Type stripping has real limitations. Because Node.js only removes types and does not run the TypeScript compiler, any feature that has to be replaced with new JavaScript throws an error.

### Enums, runtime namespaces and parameter properties

`enum`, `namespace` blocks that contain runtime code, and constructor parameter properties all need code generation. Node throws `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`. A namespace that only exports types is fine. Use a union of string literals or a plain object with `as const` instead of an enum.

```typescript
// Fails with native type stripping
enum Direction {
  Up,
  Down,
}

// Works
const Direction = { Up: 0, Down: 1 } as const;
```

The `--experimental-transform-types` flag handled these cases in some versions, but the Node.js docs say it was removed in v26.0.0, so do not build on it.

### Type-only imports need `type`

Without the `type` keyword, Node treats an import as a value import and fails at runtime.

```typescript
import type { User } from './types.ts'; // works
import { fetchUser, type UserOptions } from './user.ts'; // works
import { User } from './types.ts'; // runtime error if User is only a type
```

### File extensions and `tsconfig.json`

Imports must include the file extension, for example `./file.ts`. Node ignores `tsconfig.json`, so `paths` aliases do not work (use subpath imports that start with `#` instead). Node also refuses to run TypeScript files inside `node_modules`, and `.tsx` files and legacy decorators are not supported.

For full TypeScript support, including `tsconfig.json` and enums, the Node.js docs recommend a third-party tool such as `tsx`: `node --import=tsx your-file.ts`.

---

## No Type Checking

This is the most important thing to understand: **Node.js does not check your types**. If you pass a `string` where a `number` is expected, your code will still run and potentially fail at runtime. For full type-checking, you still need `tsc`, and [TypeScript 7.0's Go-based compiler](/blog/typescript-7-project-corsa-go-compiler-2026/), released in June 2026, makes that roughly 8x to 12x faster. If your `tsc --noEmit` is slow today, the [TypeScript performance guide](/blog/typescript-performance-large-codebases-2026/) walks through the patterns that cause it and the diagnostic loop to find them.

```typescript
function add(a: number, b: number): number {
  return a + b;
}

add("hello", "world"); // No error from Node.js. Runs. Returns "helloworld".
```

Type checking is still your responsibility. Run `tsc --noEmit` separately in CI or as a pre-commit check:

```bash
# Check types without emitting files
npx tsc --noEmit
```

Think of native TypeScript execution as separating two concerns that were always bundled together:

- **Type checking** → `tsc` (you run this for correctness)
- **Execution** → `node` (just runs the code)

---

## When You Still Need a Build Step

Native type stripping is great for scripts, tools, and development. But for production, you still want to build:

- **Bundling for the browser:** browsers do not support type stripping
- **Tree shaking and minification:** you need a bundler for this
- **Targeting older Node.js versions:** type stripping needs v22.18+ or v23.6+ to work without a flag
- **Performance in production:** pre-compiled JavaScript starts slightly faster than stripping types at runtime
- **Publishing npm packages:** publish `.js` files, not `.ts`

For applications, keep your build pipeline. For scripts and internal tools, skip it.

---

## The Practical Workflow in 2026

Newer JavaScript features, such as the [ES2026 features](/blog/es2026-javascript-features-guide/), depend on your Node.js version (its V8 engine), not on type stripping. If your Node.js version supports a feature, you can use it in a `.ts` file without a separate compilation step.

Here is what a sensible setup looks like today:

```json
// package.json
{
  "scripts": {
    "dev": "node --watch src/index.ts",
    "typecheck": "tsc --noEmit",
    "build": "tsc"
  }
}
```

- `dev` runs TypeScript directly with file watching, no compilation
- `typecheck` validates your types without running the code
- `build` compiles for production

You get the fast iteration loop of native execution during development, and proper type checking when you actually need it.

---

## Conclusion

Native TypeScript execution in Node.js removes one of the most annoying parts of the JavaScript ecosystem: the mandatory build step for TypeScript scripts. For anything that lives on the server or runs as a tool, you can now write TypeScript and just run it.

The key things to keep in mind: types are stripped, not checked. Run `tsc --noEmit` for correctness. Avoid enums, runtime namespaces and legacy decorators, and use `import type`. And for production applications, still build your code.

But for your next utility script? Just write `.ts` and run it. We earned this one.

## Frequently Asked

**Which Node.js version can run TypeScript?** Type stripping is on by default from v23.6 and v22.18, and the Node.js docs mark it stable in v24.12 and v25.2. It first appeared in v22.6 behind a flag.

**Does Node.js type check TypeScript?** No. It strips types and runs the JavaScript. Run `tsc --noEmit` for type checking.

**Does Node.js support TypeScript enums?** Not with type stripping. Use `as const` objects or string unions, or a tool like `tsx`.

**Do I need tsx or ts-node now?** Not for simple scripts on a recent Node.js. You still want one if you rely on `tsconfig.json` paths, enums or decorators.
