Skip to main content
Advertisement

9.2 Fast Transpilers — esbuild, swc, tsx

The Limits of tsc and the Rise of Transpilers

tsc (TypeScript Compiler) performs both type checking and code transformation. In large projects, this can become slow.

Fast transpilers skip type checking and only handle TypeScript → JavaScript conversion, dramatically increasing speed.

ToolLanguageSpeedType Checking
tscTypeScriptNormal✅ Included
esbuildGoVery fast (100x)❌ None
swcRustVery fast (70x)❌ None
tsx(esbuild-based)Very fast❌ None

Core principle: Use transpilers for development speed, use separate tsc type checking for type safety.


esbuild

An ultra-fast bundler and transpiler written in Go.

Installation

npm install --save-dev esbuild

Basic Usage

# TypeScript → JavaScript transpilation
npx esbuild src/index.ts --outfile=dist/index.js

# Bundling
npx esbuild src/index.ts --bundle --outfile=dist/bundle.js

# Minification
npx esbuild src/index.ts --bundle --minify --outfile=dist/bundle.min.js

# Watch mode
npx esbuild src/index.ts --bundle --watch --outfile=dist/bundle.js

Node.js Server Build

// build.ts
import * as esbuild from 'esbuild';

await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'node',
target: 'node20',
format: 'cjs', // or 'esm'
outfile: 'dist/index.js',
external: [ // Packages to exclude from bundle
'express',
'pg',
],
sourcemap: true,
});

console.log('Build complete!');

Externalizing All node_modules (Useful for Node.js Servers)

import * as esbuild from 'esbuild';

await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'node',
packages: 'external', // Externalize all node_modules
outfile: 'dist/index.js',
});

Using Plugins

import * as esbuild from 'esbuild';
import { TsconfigPathsPlugin } from '@esbuild-plugins/tsconfig-paths';

await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
plugins: [
TsconfigPathsPlugin({ tsconfig: './tsconfig.json' }),
],
outfile: 'dist/index.js',
});

package.json Scripts

{
"scripts": {
"build": "node build.js",
"build:types": "tsc --emitDeclarationOnly",
"dev": "node --watch dist/index.js",
"typecheck": "tsc --noEmit"
}
}

swc (Speedy Web Compiler)

A transpiler written in Rust, serving as an alternative to Babel. Used internally by Next.js.

Installation

npm install --save-dev @swc/core @swc/cli

.swcrc Configuration

// .swcrc
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": true
},
"target": "es2022",
"transform": {
"react": {
"runtime": "automatic" // React 17+ JSX transform
}
}
},
"module": {
"type": "commonjs" // or "es6"
},
"sourceMaps": true
}

Basic Usage

# Transform single file
npx swc src/index.ts -o dist/index.js

# Transform entire directory
npx swc src -d dist

# Watch mode
npx swc src -d dist --watch

Using with Jest (jest-transform)

npm install --save-dev @swc/jest
// jest.config.js
module.exports = {
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
};

Test execution speed is 3–5x faster than Babel + ts-jest.

Using swc with NestJS

# NestJS CLI with swc build
nest build --webpack # or
npx @nestjs/cli build --builder swc
// nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": {
"type": "swc",
"options": {
"swcrcPath": ".swcrc"
}
}
}
}

tsx

A Node.js TypeScript runner based on esbuild. Much faster than ts-node.

Installation

npm install --save-dev tsx

Basic Usage

# Run TypeScript files directly
npx tsx src/index.ts

# Watch mode (auto-restart on file changes)
npx tsx watch src/index.ts

# REPL
npx tsx

package.json Scripts

{
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"build": "tsc",
"typecheck": "tsc --noEmit"
}
}

Comparison with ts-node

# ts-node: slow (same approach as tsc)
npx ts-node src/index.ts

# tsx: fast (uses esbuild, no type checking)
npx tsx src/index.ts

Using tsx in ESM Mode

// package.json
{
"type": "module"
}
# Run ESM TypeScript files
npx tsx src/index.ts # Automatically handles ESM

Script Execution Pattern

// scripts/seed-db.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
await prisma.user.createMany({
data: [
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' },
],
});
console.log('Seeded!');
}

main().finally(() => prisma.$disconnect());
{
"scripts": {
"seed": "tsx scripts/seed-db.ts"
}
}

Trade-off Comparison

When to Use Each Tool

tsc (type checking only):
- Type validation in CI/CD pipelines
- Generating .d.ts for library publishing
- "typecheck" script

esbuild (bundle builds):
- Fast production builds
- Serverless function bundling
- When bundle size matters

swc (babel replacement):
- Improving Jest transformation speed
- NestJS development server
- Migrating from Babel plugins

tsx (development execution):
- Fast Node.js script execution
- Development server hot reload
- Running migration scripts

Strategy: Type Check + Fast Build Combination

// package.json — Recommended script setup
{
"scripts": {
"dev": "tsx watch src/index.ts", // Dev: fast execution
"build": "tsc -p tsconfig.build.json && tsc-alias", // Build: with type check
"build:fast": "esbuild src/index.ts --bundle --outfile=dist/index.js", // CI fast build
"typecheck": "tsc --noEmit", // Type check only (separate CI step)
"test": "vitest" // Tests: Vite-based (esbuild built-in)
}
}

Real-World Development Environment Setup

Optimal Node.js API Server Configuration

// package.json
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "esbuild src/index.ts --bundle --platform=node --packages=external --outfile=dist/index.js --sourcemap",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit"
}
}

Development flow:

  1. npm run dev — Start instantly with tsx (no type check, fast)
  2. npm run typecheck — Check for type errors separately
  3. npm run build — Fast production build with esbuild

CI/CD Pipeline

# .github/workflows/ci.yml
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- run: npm run typecheck # Type checking

build:
runs-on: ubuntu-latest
steps:
- run: npm run build # Build
- run: npm test # Tests (swc-based jest)

Pro Tips

1. Vite internally uses esbuild

Using Vite gives you an ultra-fast development server without separate esbuild configuration.

2. Separate type checking and emit in tsconfig

// tsconfig.json (for type checking)
{ "noEmit": true }

// tsconfig.build.json (for builds)
{ "extends": "./tsconfig.json", "noEmit": false }

3. Measuring speed

# Measure tsc build time
time tsc --noEmit

# Measure esbuild build time
time npx esbuild src/index.ts --bundle --outfile=/dev/null

Generally, esbuild/swc is 50–100x faster than tsc.

Advertisement