Skip to main content

Best TypeScript-First Build Tools 2026

·PkgPulse Team

esbuild is 45x faster than tsc for transpilation. SWC is 20x faster. Yet tsc remains the gold standard for type checking — because esbuild and SWC deliberately skip type checking entirely. The TypeScript build tooling landscape in 2026 is about combining these tools correctly, not picking one.

TL;DR

For libraries: Use tsup (esbuild-based, zero-config) or unbuild (Rollup-based, better tree-shaking). For applications: Your framework's build tool (Next.js, Vite, etc.) already handles this. For type checking: Always run tsc --noEmit separately — no other tool can replace it. For running TypeScript directly: Use tsx (fast, esbuild-based).

Key Takeaways

  • tsc: Only tool that performs type checking; transpilation is 45x slower than esbuild
  • esbuild: 45x faster than tsc for transpilation; does NOT type check
  • swc: 20x faster than tsc; does NOT type check; used by Rspack/Next.js internals
  • tsup (~1.2M weekly downloads): Most popular library bundler, uses esbuild, zero-config
  • unbuild: Rollup-based, better for libraries needing optimal tree-shaking
  • pkgroll: Rollup-based, explicit about entry points, growing adoption
  • The correct pattern: tsc --noEmit (type check) + esbuild/SWC (transpile)

The TypeScript Tooling Landscape

The tools serve different purposes:

Source (TypeScript)
    │
    ├─→ Type Checking: tsc --noEmit (required for correctness)
    │
    ├─→ Transpilation (TS → JS):
    │       tsc        (slow, correct)
    │       esbuild    (45x faster, no type check)
    │       SWC        (20x faster, no type check)
    │       Babel      (configurable, slow)
    │
    └─→ Bundling (JS → optimized JS):
            tsup       (esbuild, library-focused)
            unbuild    (Rollup, library-focused)
            pkgroll    (Rollup, library-focused)
            Vite       (Rollup + esbuild)
            Rollup     (manual configuration)

tsc: The Type Checking Foundation

Package: typescript (includes tsc) Weekly downloads: 60M+ Purpose: Type checking + transpilation (slow path)

Never use tsc for production builds in 2026. Use it only for type checking:

# Type check only (no output files)
npx tsc --noEmit

# Or in watch mode during development
npx tsc --noEmit --watch
// package.json
{
  "scripts": {
    "type-check": "tsc --noEmit",
    "build": "tsup src/index.ts --format esm,cjs --dts"
  }
}

tsconfig.json for Library Publishing

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "strict": true,
    "skipLibCheck": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

tsup: The Library Bundler Standard

Package: tsup Weekly downloads: 1.2M GitHub stars: 10K Creator: EGOIST Underlying: esbuild

tsup is the most popular TypeScript library bundler. Zero-config defaults make it productive immediately:

npm install -D tsup

Basic Library Setup

// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],    // CommonJS + ES Modules
  dts: true,                  // Generate .d.ts files
  splitting: false,           // Keep output in single files
  sourcemap: true,
  clean: true,                // Clean dist/ before build
});
// package.json
{
  "name": "my-library",
  "version": "1.0.0",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "type-check": "tsc --noEmit"
  },
  "devDependencies": {
    "tsup": "^8.0.0",
    "typescript": "^5.4.0"
  }
}

Multiple Entry Points

export default defineConfig({
  entry: {
    index: 'src/index.ts',
    cli: 'src/cli.ts',
    utils: 'src/utils/index.ts',
  },
  format: ['cjs', 'esm'],
  dts: true,
  external: ['react'], // Don't bundle peer dependencies
});

tsup Features

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],
  dts: true,
  minify: true,        // Minify output
  treeshake: true,     // Remove dead code
  shims: true,         // Add CJS/ESM shims for interop
  onSuccess: 'node dist/index.cjs', // Run after build
  banner: {
    js: '// My Library v1.0.0',
  },
  define: {
    'process.env.NODE_ENV': '"production"',
  },
});

unbuild: Rollup-Based Library Bundling

Package: unbuild Weekly downloads: 800K GitHub stars: 2.5K Creator: UnJS (Nuxt team) Underlying: Rollup + mkdist

unbuild is the choice when output optimization matters more than build speed. Rollup's tree-shaking and code splitting are superior to esbuild's for complex libraries.

npm install -D unbuild
// build.config.ts
import { defineBuildConfig } from 'unbuild';

export default defineBuildConfig({
  entries: ['./src/index'],
  declaration: true,
  rollup: {
    emitCJS: true,
    cjsBridge: true,
    esbuild: { minify: true },
  },
  externals: ['react', 'react-dom'],
});

unbuild automatically infers your build configuration from package.json exports:

// package.json — unbuild reads this automatically
{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

Why Choose unbuild Over tsup?

  • Rollup tree-shaking is more aggressive (better output for complex libraries)
  • mkdist for distributing TypeScript source files (.d.ts + .ts)
  • Better handling of CSS-in-JS and asset imports in library code
  • Part of the UnJS ecosystem (works with Nuxt, Nitro, H3)

pkgroll: Explicit Entry Points

Package: pkgroll Weekly downloads: 100K GitHub stars: 1.5K Underlying: Rollup

pkgroll reads your package.json exports field to determine what to build — no separate config file needed:

npm install -D pkgroll typescript
// package.json — pkgroll uses this as its configuration
{
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./utils": {
      "types": "./dist/utils.d.ts",
      "import": "./dist/utils.js"
    }
  },
  "scripts": {
    "build": "pkgroll"
  }
}
# Just run:
npx pkgroll

# With watch mode:
npx pkgroll --watch

pkgroll's philosophy: your package.json is the source of truth for what gets built. No separate build config file.

esbuild: The Raw Transpiler

Package: esbuild Weekly downloads: 32M GitHub stars: 38K

For scripts and non-library code, raw esbuild is fast and simple:

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

await esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/index.js',
  platform: 'node',
  target: 'node20',
  format: 'esm',
  minify: true,
  sourcemap: true,
  external: ['express', 'zod'], // Don't bundle dependencies
});

esbuild Watch Mode

const ctx = await esbuild.context({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outdir: 'dist',
  platform: 'node',
});

await ctx.watch();
console.log('Watching...');

SWC: Rust-Powered Transpilation

Package: @swc/core Weekly downloads: 15M GitHub stars: 32K

SWC is used internally by Next.js, Rspack, and Vite (via plugins). For direct use:

npm install -D @swc/core @swc/cli
// .swcrc
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": true
    },
    "transform": {
      "react": { "runtime": "automatic" }
    },
    "target": "es2022"
  },
  "module": {
    "type": "es6"
  },
  "sourceMaps": true
}
# Transpile a file
npx swc src/index.ts -o dist/index.js

# Transpile directory
npx swc src -d dist

Performance Comparison

ToolTranspilation (100 files)Type CheckingTree Shaking
tsc~10sYesNo
esbuild~0.2s (50x)NoBasic
SWC~0.5s (20x)NoBasic
tsup (esbuild)~0.3sVia tscBasic
unbuild (Rollup)~2sVia tscExcellent

For Library Development

# Build tool: tsup or unbuild
npm install -D tsup typescript

# Type check separately:
# tsc --noEmit (in CI, pre-commit, IDE)
# tsup builds with dts: true (generates .d.ts only, no type errors)

For Application Development

Use your framework's built-in tools:

  • Next.js: SWC (built-in) + turbopack
  • Vite: esbuild (dev) + Rollup (prod)
  • Remix: esbuild

For CLI Tools

# tsup with Node.js target:
tsup src/cli.ts --format cjs --dts --no-splitting

For Monorepos (TypeScript Project References)

# tsc project references for type checking:
tsc --build --verbose

# tsup for each package's output:
workspace: each package has its own tsup.config.ts

Choosing the Right Tool

Use CaseRecommended Tool
NPM library (fast build)tsup
NPM library (optimal bundle)unbuild
NPM library (package.json-driven)pkgroll
Type checking (always)tsc --noEmit
Node.js scriptesbuild direct or tsup
Next.js appBuilt-in SWC + Turbopack
Vite appBuilt-in esbuild + Rollup
Running TS directlytsx

Compare download trends for these tools on PkgPulse.

Comments

Stay Updated

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