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.jsAgent 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: TypeScriptand CLI flag docs
After implementation, run fuse-ai-pilot:sniper for validation.
Use when
- Running
.ts/.mts/.ctsfiles directly withnode file.ts(no bundler) - Deciding between native type stripping and a full loader (
tsx) - Setting up an ESM-only Node project,
--watchmode, ornode:test - Migrating a script/CLI/hook off
ts-nodeto 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 --noEmitseparately for safety. tsconfig.jsonis ignored at runtime -paths, downleveling, and JS target lowering do not apply. Native stripping only erases inline types.- Non-erasable syntax errors out -
enum,namespacewith runtime code, parameter properties, and import aliases throwERR_UNSUPPORTED_TYPESCRIPT_SYNTAX. - Use
import type/verbatimModuleSyntax- Value imports of types crash at runtime; thetypekeyword is mandatory for type-only imports. - File extensions are mandatory -
import './file.ts', not./file..tsxis 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 / 26 features | references/node24-features.md | Watch mode, node:test, ESM resolution, relevant built-ins, Node 26 changes |
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/.mtswith explicit import extensions - Keep
tsc --noEmitin CI for real type safety alongside runtime stripping - Reach for
tsxthe moment you needpaths, decorators,enum, or.tsx
DON'T
- Assume
tsconfigpathsortargetdownleveling work at runtime — they don't - Publish
.tsfiles insidenode_modules— Node refuses to strip them - Rely on native stripping for decorators (TC39 Stage 3, not transformed)