Skip to content

tsup

Build & PackagingBuild Tool / BundlerTypeScript

What it is

tsup bundles TypeScript libraries with almost no configuration, producing ESM and CommonJS output plus declaration files in one command.

Point tsup at an entry file and specify the formats. It handles bundling, minification, declaration generation and tree-shaking metadata.

Installation

npm install -D tsup

Getting started

The smallest useful thing you can do with it, and what each part means.

Dual-format library build
// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,          // emit .d.ts
  sourcemap: true,
  clean: true,
  treeshake: true,
});
dts runs a separate declaration build, which is the slowest part. Turn it off during watch mode and enable it only for the publish build.
The package.json that goes with it
{
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  },
  "files": ["dist"]
}
The `types` condition must come first inside exports — resolvers take the first match, and putting it last is why consumers sometimes see `any`.

Advanced usage

Where the library earns its place over a simpler alternative.

Multiple entries and externals
export default defineConfig({
  entry: { index: 'src/index.ts', cli: 'src/cli.ts' },
  format: ['esm'],
  external: ['react', 'react-dom'],  // never bundle peer dependencies
  banner: { js: '#!/usr/bin/env node' },
  onSuccess: 'node dist/cli.js --smoke-test',
});
Bundling a peer dependency such as React ships a second copy to consumers and breaks hooks. Listing peers as external is essential for library authors.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Consumers see any for your types
The types condition is missing or ordered after import/require in exports. It must be first.
Two copies of React at runtime
React was bundled instead of externalised. Add it to external and to peerDependencies.

Best practices

  • Mark every peer dependency as external — bundling React or Vue breaks consumers.
  • Put the types condition first in package.json exports.
  • Disable dts in watch mode; it dominates build time.
  • Use tsup for libraries and Vite for applications — they solve different problems.

Background

Why it exists, and what it was reacting to.

Built on esbuild by Kane Wallmann and egoist, tsup exists because publishing a dual-format npm package used to require a rollup config, a tsc pass and careful package.json exports — work that is nearly identical for every library.