cheat sheet
ts-node
Daily-driver reference for the ts-node CLI — REPL, transpile-only mode, ESM loader, common script patterns.
ts-node — CLI
What it is
ts-node is the original TypeScript-Execute CLI for Node.js. It runs .ts files by invoking the real TypeScript compiler via the TS API, then handing the result to Node. New projects typically prefer tsx (faster, simpler ESM), but ts-node remains the right choice when you need genuine TS type-checking at runtime, the TS-aware REPL, paths aliases handled by the compiler, or emitDecoratorMetadata for legacy NestJS / TypeORM stacks.
For deep package context (peer deps, alternatives, security), see packages-npm/npm-ts-node. This page covers daily CLI use.
Install
npm install -D ts-node typescript
Output: binaries ts-node, ts-node-esm, ts-node-script, ts-node-transpile-only in node_modules/.bin/.
Day-to-day commands
| Command | What it does |
|---|---|
ts-node file.ts | Compile + run a TS file with full type-checking |
ts-node --transpile-only file.ts | Skip type-checking (faster, like tsx) |
ts-node | Launch the TypeScript REPL |
ts-node-esm file.ts | Run in ESM mode |
ts-node --esm file.ts | Same as above, flag form |
ts-node --swc file.ts | Use SWC transpiler instead of tsc (skips types) |
ts-node -r tsconfig-paths/register file.ts | Resolve TS paths aliases |
node --loader ts-node/esm file.ts | Use ts-node as a Node ESM loader |
Common scenarios
Launch the TypeScript REPL
ts-node
Output:
> const greet = (name: string) => `Hi, ${name}`
undefined
> greet("Alice")
'Hi, Alice'
> greet(42)
TSError: ⨯ Unable to compile TypeScript:
file.ts:1:11 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
The REPL respects tsconfig.json strict, paths, lib. Still the best interactive TS environment.
Run a script in transpile-only mode
ts-node --transpile-only ./scripts/seed.ts
Output:
[seed] inserted 1000 rows
--transpile-only skips the type checker — roughly 5× faster. Pair with tsc --noEmit in a pre-commit hook so type errors don't disappear.
ESM mode with top-level await
ts-node-esm ./scripts/migrate.ts
Output:
connected
3 migrations applied
// scripts/migrate.ts
import { Client } from "pg";
const db = new Client();
await db.connect();
console.log("connected");
Output:
(node:12345) ExperimentalWarning: --experimental-loader may be removed in the future...
connected
The experimental warning is harmless. New projects should prefer tsx for ESM scripts.
Resolve paths aliases
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
}
}
npm install -D tsconfig-paths
ts-node -r tsconfig-paths/register ./src/server.ts
Output:
added 1 package in 1s
Server listening on http://localhost:3000
Or wire it into config:
{
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
Then ts-node ./src/server.ts picks it up automatically.
Use SWC for speed
npm install -D @swc/core @swc/helpers
Output:
added 2 packages in 3s
// tsconfig.json
{
"ts-node": { "swc": true }
}
ts-node ./script.ts
Output:
[script] ran (~3× faster than tsc)
SWC mode skips type-checking and uses Rust transpile. Effectively turns ts-node into a slower tsx.
Mocha integration
// .mocharc.json
{
"require": ["ts-node/register"],
"extensions": ["ts"],
"spec": "test/**/*.test.ts"
}
npx mocha
Output:
user service
✓ creates a user
✓ deletes a user
2 passing (45ms)
Debug under VS Code
// .vscode/launch.json
{
"type": "node",
"request": "launch",
"name": "Debug TS file",
"runtimeExecutable": "node",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${file}"],
"skipFiles": ["<node_internals>/**"]
}
Hit F5 with a .ts file open — breakpoints land on TS source thanks to source maps.
Useful flags
| Flag | What it does |
|---|---|
--transpile-only | Skip type-checking (faster) |
--esm | Run in ESM mode |
--swc | Use SWC transpiler (skips types) |
--compiler-options '{"key":"value"}' | Override tsconfig compilerOptions inline |
--project <path> | Use a specific tsconfig.json |
--files | Force-include files in files/include even if not imported |
--ignore-diagnostics 2304,2307 | Suppress specific TS error codes |
--log-error | Print errors but continue executing |
--pretty | Coloured diagnostic output |
-r <module> | Pre-load a CommonJS module (Node's --require shorthand) |
Environment variables (all prefixed TS_NODE_):
| Env var | Purpose |
|---|---|
TS_NODE_PROJECT | Path to tsconfig.json |
TS_NODE_TRANSPILE_ONLY=true | Equivalent to --transpile-only |
TS_NODE_IGNORE_DIAGNOSTICS | Comma-separated error codes to ignore |
TS_NODE_COMPILER_OPTIONS | JSON string of compilerOptions overrides |
Configuration
ts-node reads a ts-node block in tsconfig.json:
{
"compilerOptions": { /* ... */ },
"ts-node": {
"transpileOnly": true,
"esm": true,
"swc": false,
"require": ["tsconfig-paths/register"],
"compilerOptions": {
"module": "commonjs"
}
}
}
The ts-node.compilerOptions override is useful when your main compilerOptions targets ESM but ts-node needs CommonJS (or vice versa) for a particular script.
Common pitfalls
Error [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"in ESM mode. Usets-node-esmor--esm, not plaints-node.TS2307: Cannot find module '@/utils'. Addtsconfig-paths/registerto the loader chain.- Slow startup (5+ seconds). Use
--transpile-onlyor--swc. The TS compiler is genuinely slow on cold starts. emitDecoratorMetadatanot working. Only the real TS compiler (the default ts-node mode) emits decorator metadata.--transpile-onlyand--swcskip it.Cannot use import statement outside a module. ESM/CJS confusion — add"type": "module"or usets-node-esm.- Memory ballooning under long-running dev. TS compiler keeps program state in memory. Restart periodically; or move to
tsx.
See also
- Packages: npm-ts-node — versioning, ecosystem
- JavaScript: tsx — modern successor
- JavaScript: typescript — language reference