← All articles
BUILD TOOLS tsup: Bundle TypeScript Packages Without Config 2026-03-04 · 3 min read · tsup · typescript · bundler

tsup: Bundle TypeScript Packages Without Config

Build Tools 2026-03-04 · 3 min read tsup typescript bundler esbuild npm package esm cjs developer tools

Publishing a TypeScript npm package requires bundling to JavaScript, generating type declarations, supporting both ESM and CommonJS, and managing sourcemaps. Most bundler setups require significant configuration. tsup handles all of this with minimal configuration, powered by esbuild under the hood.

Install

npm install --save-dev tsup
# or
pnpm add -D tsup

Zero-Config Start

For a simple package with src/index.ts as the entry:

npx tsup src/index.ts

This outputs:

dist/
  index.js      # CommonJS
  index.mjs     # ESM
  index.d.ts    # TypeScript declarations

No config file needed for basic cases.

package.json Setup

{
  "name": "my-package",
  "version": "1.0.0",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch"
  }
}

Configuration File

For more complex packages, create tsup.config.ts:

import { defineConfig } from "tsup";

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["cjs", "esm"],
  dts: true,                 // Generate .d.ts files
  splitting: false,          // Disable code splitting for libraries
  sourcemap: true,
  clean: true,               // Clean dist/ before build
  minify: false,             // Don't minify (readable library code)
  external: ["react"],       // Don't bundle peer dependencies
  outDir: "dist",
});

Multiple Entry Points

For packages exporting multiple subpaths:

export default defineConfig({
  entry: {
    index: "src/index.ts",
    utils: "src/utils.ts",
    cli: "src/cli.ts",
  },
  format: ["cjs", "esm"],
  dts: true,
});

With corresponding package.json exports:

{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js"
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "require": "./dist/utils.js"
    }
  }
}

CLI Tools

For CLI packages, use the banner option to add the shebang:

export default defineConfig({
  entry: ["src/cli.ts"],
  format: ["cjs"],          // CLI tools typically ship as CJS
  dts: false,               // No types needed for CLI
  banner: {
    js: "#!/usr/bin/env node",
  },
});
{
  "bin": {
    "my-cli": "./dist/cli.js"
  }
}

Watch Mode for Development

tsup --watch

Rebuilds on file changes. Useful during development of a package that you're testing in another project via npm link or workspace references.

Type Declarations

tsup uses TypeScript's compiler API to generate .d.ts files when dts: true is set. This is slower than the JS bundling (esbuild doesn't generate types) but correct.

// If you only need types for some entries:
export default defineConfig({
  entry: ["src/index.ts", "src/cli.ts"],
  dts: {
    entry: "src/index.ts",  // Only generate types for index, not cli
  },
});

Treeshaking

export default defineConfig({
  treeshake: true,   // Remove unused exports
  splitting: true,   // Enable code splitting (ESM only)
});

Treeshaking is most valuable for large packages where consumers may only use part of the API.

Environment Variables and Defines

export default defineConfig({
  define: {
    "process.env.NODE_ENV": JSON.stringify("production"),
    __VERSION__: JSON.stringify(process.env.npm_package_version),
  },
});

Comparison: tsup vs Other Options

tsup Rollup tsc esbuild
Config needed Minimal Extensive tsconfig Moderate
Speed Very fast Moderate Slow Fastest
Type declarations Built-in Plugin Built-in No
ESM + CJS output One command Multiple configs Limited Manual
Maturity 2021+ Established Established

tsup hits the sweet spot for library packages: fast enough (esbuild core), correct type declarations, dual ESM/CJS output without significant configuration.

Common Patterns

React Component Library

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["cjs", "esm"],
  dts: true,
  external: ["react", "react-dom"],
  jsx: "react-jsx",          // Handle JSX
  sourcemap: true,
});

Pure ESM Package

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["esm"],           // ESM only
  dts: true,
});
{
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  }
}

Monorepo Package

In a pnpm workspace, tsup works with zero additional configuration:

packages/
  ui/
    src/index.ts
    tsup.config.ts
    package.json
  utils/
    src/index.ts
    tsup.config.ts
    package.json

Each package has its own tsup.config.ts. Turborepo or Nx handles build ordering.

Size Analysis

# Check bundle size after build
npx tsup --analyze

For detailed analysis, integrate with bundlephobia or bundlesize in CI.

tsup is the default choice for new TypeScript package projects — it handles the common cases correctly out of the box and gets out of the way. The tsup documentation covers advanced cases including custom plugins via esbuild's plugin API.