setup-tsup
Set up tsup (esbuild-based bundler) for a TypeScript package. Use when you need single-file bundled output, faster builds, and better startup time for Node.js CLIs or libraries. Covers tsup config, bi
Files1
View on GitHubSKILL.md.claude/skills/setup-tsup/SKILL.md
GitHubSet Up tsup Build
Goal
Replace or add tsup as the build tool for a TypeScript package. Keep tsc --noEmit for type-checking only.
Why
- Single-file bundled output = 2-5x faster startup (fewer fs reads during module resolution)
- Tree-shakes unused code from dependencies
- esbuild-based = sub-second builds vs multi-second tsc
Steps
1. Install tsup
pnpm add -D tsup
2. Create tsup.config.ts
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: 'node22',
clean: true,
splitting: false,
sourcemap: true,
dts: false,
// For CLIs: add shebang
banner: {
js: '#!/usr/bin/env node',
},
// Native/dynamic deps that shouldn't be bundled
external: [],
})
For libraries (not CLIs), remove the banner and consider dts: true for declaration files.
3. Update package.json scripts
{
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"ts:check": "tsc --noEmit"
}
}
4. Update bin entry point (CLIs only)
The bin file should point to the tsup output. tsup outputs to dist/ by default:
- Verify the
binfield referencesdist/index.js(ordist/index.mjs) - Since tsup adds the shebang via
banner, the bin file can point directly to the bundled output
5. Verify
pnpm build # Should produce dist/index.js (single file)
pnpm ts:check # Type checking still works
node dist/index.js --help # CLI works (if applicable)
6. Update .gitignore
Ensure dist/ is in .gitignore.
Gotchas
- If any dependency uses
__dirnameorrequire.resolve, tsup may need those deps inexternal - Dynamic
import()calls are preserved by esbuild — this is fine - Keep
prepareorprepublishOnlyscript aspnpm buildfor npm publish workflow - For ESM packages, ensure
"type": "module"in package.json