Introduction
tsup makes shipping TypeScript libraries almost too easy. Run one command and you get CJS + ESM bundles, .d.ts type declarations, source maps, and a watch mode — without writing Rollup config, tsc invocation, or a custom build script. It's built on esbuild, so builds finish in milliseconds.
With over 11,000 GitHub stars, tsup is the go-to library bundler for the TypeScript ecosystem. It powers tRPC, antfu's packages, and thousands of npm libraries.
What tsup Does
tsup takes entry files, bundles them with esbuild, and optionally generates .d.ts via the TypeScript compiler (or rollup-plugin-dts for speed). It handles multiple output formats, code splitting, minification, source maps, tree shaking, and watch mode — all configurable by CLI flags or a tsup.config.ts file.
Architecture Overview
package source (src/*.ts)
|
[tsup CLI]
|
+-------+-------+-------+
| | | |
[esbuild] [DTS] [Watcher] [Publish hints]
bundle tsc-based (--watch mode)
+ tree-shake or rollup-plugin-dts
|
dist/
index.js (CJS)
index.mjs (ESM)
index.d.ts (types)
*.map (source maps)Self-Hosting & Configuration
// tsup.config.ts
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts", "src/cli.ts"],
format: ["cjs", "esm"],
dts: true,
splitting: true,
sourcemap: true,
clean: true,
treeshake: true,
minify: false,
target: "node18",
external: ["react"],
banner: { js: "#!/usr/bin/env node" }, // for CLI entries
onSuccess: "node dist/cli.js --smoke",
});Key Features
- Zero config — sensible defaults for TypeScript libraries
- Multiple formats — ESM, CJS, IIFE in a single run
- Type declarations —
--dtsemits.d.tsalongside the bundle - esbuild speed — sub-second builds for most libraries
- Watch mode — incremental rebuilds for development
- Code splitting — share chunks across entries
- Tree shaking — remove unused exports
- CLI or config file — flags for quick use, tsup.config.ts for projects
Comparison with Similar Tools
| Feature | tsup | unbuild | tsdx | vite (lib mode) | Rollup |
|---|---|---|---|---|---|
| Config complexity | Very Low | Low | Low | Low | High |
| Speed | Very Fast | Fast | Slow (tsc) | Fast | Moderate |
| DTS | Yes (--dts) | Yes | Yes | Plugin needed | Plugin needed |
| Multi-format | Yes | Yes | Yes | Yes | Yes (manual) |
| Tree shaking | Good | Good | Good | Excellent | Excellent |
| Best For | Any TS lib | UnJS / Nuxt-style | Legacy React libs | Vue/React libs | Complex control |
FAQ
Q: tsup vs Rollup — do I ever pick Rollup? A: Pick Rollup when you need precise control over chunking, advanced plugins, or maximum tree-shaking. For 95% of TypeScript libraries, tsup produces equivalent output with much less config.
Q: tsup vs unbuild? A: Both zero-config. unbuild is from UnJS (Nitro/Nuxt), uses Rollup under the hood, and has stricter stub/shim behavior. tsup uses esbuild and tends to build faster. Functionally similar for most libraries.
Q: Does tsup emit correct DTS for complex generics?
A: --dts runs the TypeScript compiler (tsc) — it emits whatever your tsc would. --dts-resolve uses rollup-plugin-dts which is faster but stricter.
Q: Can I build a CLI with tsup?
A: Yes. Add banner: { js: "#!/usr/bin/env node" } and configure a binary in package.json. tsup handles shebangs, externals, and watch-restart for CLI dev.
Sources
- GitHub: https://github.com/egoist/tsup
- Docs: https://tsup.egoist.dev
- Author: EGOIST
- License: MIT