tsx vs ts-node vs Bun: Running TypeScript Directly in 2026
ts-node takes 500ms+ to start a TypeScript file. tsx takes 20ms. Bun is even faster. For scripts, CLIs, and development tools where you run TypeScript files directly, this difference compounds into hours of wasted developer time per year. And since Node.js 22.18+, there's a fourth option: native TypeScript support with zero dependencies.
TL;DR
tsx is the best drop-in replacement for ts-node in 2026 — 25x faster, zero config, no peer dependencies. Bun is faster still and is the right choice for new projects where you want a complete runtime replacement. ts-node remains valid for projects that need actual TypeScript type checking at runtime. Node.js --strip-types (v22.18+) is the new zero-overhead option for simple scripts.
Key Takeaways
- ts-node: 37M weekly npm downloads (legacy dominance); startup ~500ms
- tsx: 32M weekly npm downloads (overtaking ts-node); startup ~20ms (25x faster)
- Bun: 3M weekly downloads; startup ~5ms; built-in TypeScript, no install needed
- Node.js 22.18+ has native TypeScript "type stripping" — no extra package required
- tsx is built on esbuild (no type checking); ts-node uses TypeScript compiler (with type checking)
- All three support
import,require, ESM, CJS, and JSX/TSX
The TypeScript Execution Landscape
Running TypeScript directly (without a separate tsc build step) is essential for:
- Node.js scripts and CLIs
- Development tools and automation
- Test files (Vitest, Jest with tsx)
- Rapid prototyping
- One-off scripts in CI/CD
The tools differ fundamentally in what they actually do:
| Tool | Method | Type Checking | Speed |
|---|---|---|---|
| ts-node | TypeScript compiler | Yes (optional) | Slow |
| tsx | esbuild (strip types) | No | Fast |
| Bun | Zig runtime (strip types) | No | Fastest |
| Node.js --strip-types | V8 (strip types) | No | Fast |
ts-node
Package: ts-node
Weekly downloads: 37M
GitHub stars: 13K
ts-node is the original TypeScript execution solution for Node.js. It registers a require/import hook that transpiles TypeScript on the fly using the TypeScript compiler.
Installation
npm install -D ts-node typescript @types/node
Basic Usage
# Run a TypeScript file
npx ts-node src/script.ts
# REPL
npx ts-node
# ESM support
npx ts-node --esm src/script.ts
Configuration (tsconfig.json)
{
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node",
"transpileOnly": true // Disable type checking for speed
}
}
Type Checking at Runtime
ts-node's unique feature: actual TypeScript type checking during execution:
# Full type checking (slow, ~500ms+)
npx ts-node src/script.ts
# No type checking (faster, ~150ms)
npx ts-node --transpileOnly src/script.ts
# SWC mode (fast, ~50ms, still no type check but faster transpile)
npx ts-node --swc src/script.ts # Requires @swc/core
ts-node Limitations
- Slow startup (TypeScript compiler initialization)
- ESM support is awkward (requires
--esmflag and.mtsextension or package.json"type": "module") - Requires TypeScript as a peer dependency
- Complex configuration for monorepos
tsx
Package: tsx
Weekly downloads: 32M
GitHub stars: 12K
Creator: Hiroki Osame
tsx (TypeScript Execute) uses esbuild under the hood to strip TypeScript types and run the result through Node.js. It's a drop-in replacement for ts-node with 25x faster startup.
Installation
npm install -D tsx
# Or run without installing:
npx tsx src/script.ts
Basic Usage
# Drop-in ts-node replacement
npx tsx src/script.ts
# Watch mode (reruns on file changes)
npx tsx watch src/server.ts
# REPL
npx tsx
No Configuration Required
tsx works without a config file. It handles:
- TypeScript and TSX/JSX
- CommonJS and ES Modules
- Path aliases (via tsconfig.json
paths) import.meta,__dirname,__filenamein both CJS and ESM
// This just works with tsx:
import { readFile } from 'fs/promises';
import path from 'path';
const data = await readFile(path.join(__dirname, 'data.json'), 'utf-8');
console.log(JSON.parse(data));
tsx vs ts-node Speed
ts-node (TypeScript compiler): ~500ms startup
ts-node --transpileOnly: ~150ms startup
ts-node --swc: ~50ms startup
tsx: ~20ms startup
For a script that runs in 100ms, the difference between ts-node's 500ms startup and tsx's 20ms is massive.
Registering tsx as a Loader
# Node.js scripts with tsx as loader
node --import tsx/esm src/script.ts
# Or in package.json:
"node --import tsx/esm src/script.ts"
tsx in package.json Scripts
{
"scripts": {
"dev": "tsx watch src/server.ts",
"script": "tsx scripts/migrate.ts",
"seed": "tsx scripts/seed.ts"
}
}
Watch Mode
tsx's watch mode reruns your file on any dependency change:
npx tsx watch src/server.ts
# Restarts automatically on file changes
# Works with --env-file, --loader, etc.
This replaces nodemon + ts-node setups:
// Before: complex nodemon + ts-node setup
"dev": "nodemon --exec ts-node src/server.ts --watch src --ext ts"
// After: simple tsx watch
"dev": "tsx watch src/server.ts"
tsx Limitations
- No type checking (esbuild strips types without checking them)
- Not a Node.js runtime (still runs on Node.js)
- Some edge cases with decorators and experimental TypeScript features
Bun
Package: bun (installed globally, not via npm)
npm package for scripts: Available but optional
Weekly npm downloads: 3M (growing fast)
GitHub stars: 75K
Bun is a complete JavaScript runtime (not a Node.js tool) with built-in TypeScript support. It's faster than tsx and includes a package manager, test runner, bundler, and HTTP server.
Installation
# Install Bun runtime
curl -fsSL https://bun.sh/install | bash
# Or via npm (for scripts only):
npm install -g bun
Running TypeScript
# Run a TypeScript file (no config needed)
bun run src/script.ts
# Watch mode
bun --watch src/script.ts
# Or use as npm script runner
bun run dev # Reads package.json scripts
Bun vs tsx vs ts-node Speed
# Startup time for "console.log('hello')" in TypeScript:
ts-node: ~520ms
tsx: ~18ms
bun: ~5ms
# For a complex script with 10+ imports:
ts-node: ~1200ms
tsx: ~35ms
bun: ~8ms
Bun's TypeScript Features
// Bun supports TypeScript decorators (both legacy and TC39)
// Bun supports all TypeScript features
// Bun has built-in types via bunx bun-types
// This all works without config:
const server = Bun.serve({
port: 3000,
fetch(request) {
return new Response('Hello World!');
},
});
Bun as npm Package Manager
# 3x faster package installs than npm
bun install # Reads package.json
bun add express # Add dependency
bun remove lodash # Remove dependency
# 25x faster than npm in benchmarks
Bun's Limitations
- Not 100% Node.js API compatible (some Node.js modules don't work)
- Different from Node.js in subtle ways (may cause issues with complex packages)
- Requires Bun runtime to be installed (not available in all CI environments)
- Smaller ecosystem of documentation, answers, and guides
Node.js Native TypeScript (--strip-types)
Since Node.js 22.18 (July 2025) and stable in v25.2.0, Node.js supports TypeScript natively via type stripping:
# No extra packages needed!
node --experimental-strip-types src/script.ts
# or (22.18+, enabled by default):
node src/script.ts # .ts files work automatically
// src/script.ts
const greeting: string = 'Hello from native TypeScript!';
console.log(greeting);
node src/script.ts
# Hello from native TypeScript!
Limitations of --strip-types:
- No TypeScript transformations (decorators, enums, namespaces need
--transform-typesflag) - Only type annotations are stripped — no transpilation to different JS versions
- For full TypeScript syntax support, still need tsx or Bun
Comparison Table
| Feature | ts-node | tsx | Bun | Node --strip-types |
|---|---|---|---|---|
| Startup time | ~500ms | ~20ms | ~5ms | ~15ms |
| Type checking | Optional | No | No | No |
| ESM support | Awkward | Native | Native | Native |
| CJS support | Yes | Yes | Yes (compat) | Yes |
| Watch mode | nodemon | Yes (built-in) | Yes (--watch) | No |
| No install | No | npx | Yes (binary) | Yes (built-in) |
| Node.js compat | Full | Full | Partial | Full |
| Decorators | Yes | Yes | Yes | No |
| npm/yarn compat | Yes | Yes | Bun-native | Yes |
Migration from ts-node to tsx
In most cases, it's a one-line change:
// package.json — before
{
"scripts": {
"dev": "ts-node src/server.ts",
"script": "ts-node scripts/migrate.ts"
}
}
// After
{
"scripts": {
"dev": "tsx watch src/server.ts",
"script": "tsx scripts/migrate.ts"
}
}
npm uninstall ts-node
npm install -D tsx
When to Choose Each
Choose tsx if:
- You want the fastest drop-in ts-node replacement
- You're staying on Node.js but want better TypeScript DX
- Watch mode for dev server restarts is needed
- CI environments don't have Bun installed
Choose Bun if:
- Starting a new project from scratch
- Maximum speed is the priority
- You want the runtime + bundler + test runner in one tool
- Node.js compatibility isn't a concern for your dependencies
Choose ts-node if:
- You need actual TypeScript type checking during execution
- Decorators and complex TypeScript features are required
- Existing ts-node configuration is complex to migrate
Choose Node.js --strip-types if:
- You're on Node.js 22.18+ and want zero dependencies
- Your TypeScript code doesn't use decorators or enums
- Simplicity is the priority
The 2026 Standard
Most new TypeScript projects in 2026 use tsx for development and running scripts:
npm install -D tsx typescript @types/node
{
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js", # Compiled output in production
"build": "tsup src/index.ts",
"type-check": "tsc --noEmit"
}
}
Compare these packages on PkgPulse.
See the live comparison
View tsx vs. ts node vs bun on PkgPulse →