Skip to main content

tsx vs ts-node vs Bun: Running TypeScript Directly in 2026

·PkgPulse Team

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:

ToolMethodType CheckingSpeed
ts-nodeTypeScript compilerYes (optional)Slow
tsxesbuild (strip types)NoFast
BunZig runtime (strip types)NoFastest
Node.js --strip-typesV8 (strip types)NoFast

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 --esm flag and .mts extension 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, __filename in 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-types flag)
  • Only type annotations are stripped — no transpilation to different JS versions
  • For full TypeScript syntax support, still need tsx or Bun

Comparison Table

Featurets-nodetsxBunNode --strip-types
Startup time~500ms~20ms~5ms~15ms
Type checkingOptionalNoNoNo
ESM supportAwkwardNativeNativeNative
CJS supportYesYesYes (compat)Yes
Watch modenodemonYes (built-in)Yes (--watch)No
No installNonpxYes (binary)Yes (built-in)
Node.js compatFullFullPartialFull
DecoratorsYesYesYesNo
npm/yarn compatYesYesBun-nativeYes

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.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.