It also covers when native stripping is insufficient and a full loader (tsx) is needed —
paths, decorators, enum, or .tsx — plus setting up an ESM-only Node project, --watch mode,
and node:test, and migrating a script/CLI off ts-node.
Out of scope: Bun runtime specifics belong to ts-runtime-bun; tsconfig configuration details
belong to ts-config.
TypeScript on Node.js
Agent Workflow (MANDATORY)
Before ANY implementation, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Inspect existing
package.json, tsconfig.json, entry scripts
- fuse-ai-pilot:research-expert - Verify latest Node LTS + type-stripping behavior via Context7/Exa
- mcp__context7__query-docs - Check Node
Modules: TypeScript and CLI flag docs
After implementation, run fuse-ai-pilot:sniper for validation.
Use when
- Running
.ts/.mts/.cts files directly with node file.ts (no bundler)
- Deciding between native type stripping and a full loader (
tsx)
- Setting up an ESM-only Node project,
--watch mode, or node:test
- Migrating a script/CLI/hook off
ts-node to Node's built-in support
Do NOT use for
- Bun runtime or
bun test → use ts-runtime-bun
- Linting / formatting choices → use ts-lint-format
- Framework runtimes (Next.js, Astro) that own their own transpile pipeline
- Browser/bundled output → use a bundler skill
Critical Rules
- Type stripping is erase-only - Node replaces types with whitespace and does NO type checking. Run
tsc --noEmit separately for safety.
tsconfig.json is ignored at runtime - paths, downleveling, and JS target lowering do not apply. Native stripping only erases inline types.
- Non-erasable syntax errors out -
enum, namespace with runtime code, parameter properties, and import aliases throw ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX.
- Use
import type / verbatimModuleSyntax - Value imports of types crash at runtime; the type keyword is mandatory for type-only imports.
- File extensions are mandatory -
import './file.ts', not ./file. .tsx is unsupported by native stripping.
Architecture
project/
├── package.json # "type": "module"
├── tsconfig.json # noEmit, erasableSyntaxOnly, verbatimModuleSyntax
├── src/
│ ├── index.ts # node src/index.ts
│ └── interfaces/ # type-only modules (import type)
└── test/
└── unit.test.ts # node --test (node:test)
→ See node-esm-setup.md for a complete setup
Reference Guide
Concepts
| Topic |
Reference |
When to Consult |
| Type Stripping |
type-stripping.md |
Running .ts natively, understanding what erases and what errors |
| When tsx |
tsx-when-needed.md |
Native stripping is insufficient (paths, enums, decorators, .tsx) |
| Node 24 features |
references/node24-features.md |
Watch mode, node:test, ESM resolution, relevant built-ins |
Templates
| Template |
When to Use |
| node-esm-setup.md |
Starting an ESM Node + native TS project |
Best Practices
DO
- Set
"type": "module" and use .ts/.mts with explicit import extensions
- Keep
tsc --noEmit in CI for real type safety alongside runtime stripping
- Reach for
tsx the moment you need paths, decorators, enum, or .tsx
DON'T
- Assume
tsconfig paths or target downleveling work at runtime — they don't
- Publish
.ts files inside node_modules — Node refuses to strip them
- Rely on native stripping for decorators (TC39 Stage 3, not transformed)
1---2name: ts-runtime-node3description: Use when running TypeScript directly on Node.js without a build step — native type stripping, its limits, or when to reach for tsx. Not for Bun (ts-runtime-bun).4---56<objective>7This skill covers running .ts/.mts/.cts files directly on Node 24 LTS via native type8stripping: what erases cleanly versus what throws ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX (enum,9namespace with runtime code, parameter properties, import aliases), why tsconfig.json10paths/downleveling are ignored at runtime, and mandatory explicit file extensions and import11type usage.1213It also covers when native stripping is insufficient and a full loader (tsx) is needed —14paths, decorators, enum, or .tsx — plus setting up an ESM-only Node project, --watch mode,15and node:test, and migrating a script/CLI off ts-node.1617Out of scope: Bun runtime specifics belong to ts-runtime-bun; tsconfig configuration details18belong to ts-config.19</objective>2021# TypeScript on Node.js2223## Agent Workflow (MANDATORY)2425Before ANY implementation, spawn 3 agents in parallel, one `Agent` call each with a `name`:26271. **fuse-ai-pilot:explore-codebase** - Inspect existing `package.json`, `tsconfig.json`, entry scripts282. **fuse-ai-pilot:research-expert** - Verify latest Node LTS + type-stripping behavior via Context7/Exa293. **mcp__context7__query-docs** - Check Node `Modules: TypeScript` and CLI flag docs3031After implementation, run **fuse-ai-pilot:sniper** for validation.3233## Use when3435- Running `.ts`/`.mts`/`.cts` files directly with `node file.ts` (no bundler)36- Deciding between native **type stripping** and a full loader (`tsx`)37- Setting up an ESM-only Node project, `--watch` mode, or `node:test`38- Migrating a script/CLI/hook off `ts-node` to Node's built-in support3940## Do NOT use for4142- Bun runtime or `bun test` → use [ts-runtime-bun](../ts-runtime-bun/SKILL.md)43- Linting / formatting choices → use [ts-lint-format](../ts-lint-format/SKILL.md)44- Framework runtimes (Next.js, Astro) that own their own transpile pipeline45- Browser/bundled output → use a bundler skill4647## Critical Rules48491. **Type stripping is erase-only** - Node replaces types with whitespace and does NO type checking. Run `tsc --noEmit` separately for safety.502. **`tsconfig.json` is ignored at runtime** - `paths`, downleveling, and JS target lowering do not apply. Native stripping only erases inline types.513. **Non-erasable syntax errors out** - `enum`, `namespace` with runtime code, parameter properties, and import aliases throw `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`.524. **Use `import type` / `verbatimModuleSyntax`** - Value imports of types crash at runtime; the `type` keyword is mandatory for type-only imports.535. **File extensions are mandatory** - `import './file.ts'`, not `./file`. `.tsx` is unsupported by native stripping.5455## Architecture5657```58project/59├── package.json # "type": "module"60├── tsconfig.json # noEmit, erasableSyntaxOnly, verbatimModuleSyntax61├── src/62│ ├── index.ts # node src/index.ts63│ └── interfaces/ # type-only modules (import type)64└── test/65 └── unit.test.ts # node --test (node:test)66```6768→ See [node-esm-setup.md](references/templates/node-esm-setup.md) for a complete setup6970## Reference Guide7172### Concepts7374| Topic | Reference | When to Consult |75|-------|-----------|-----------------|76| **Type Stripping** | [type-stripping.md](references/type-stripping.md) | Running `.ts` natively, understanding what erases and what errors |77| **When tsx** | [tsx-when-needed.md](references/tsx-when-needed.md) | Native stripping is insufficient (paths, enums, decorators, `.tsx`) |78| **Node 24 features** | [references/node24-features.md](references/node24-features.md) | Watch mode, `node:test`, ESM resolution, relevant built-ins |7980### Templates8182| Template | When to Use |83|----------|-------------|84| [node-esm-setup.md](references/templates/node-esm-setup.md) | Starting an ESM Node + native TS project |8586## Best Practices8788### DO89- Set `"type": "module"` and use `.ts`/`.mts` with explicit import extensions90- Keep `tsc --noEmit` in CI for real type safety alongside runtime stripping91- Reach for `tsx` the moment you need `paths`, decorators, `enum`, or `.tsx`9293### DON'T94- Assume `tsconfig` `paths` or `target` downleveling work at runtime — they don't95- Publish `.ts` files inside `node_modules` — Node refuses to strip them96- Rely on native stripping for decorators (TC39 Stage 3, not transformed)