Migrating from tsup to tsdown
Knowledge base for AI agents to migrate tsup projects to tsdown — the Rolldown-powered library bundler.
When to Use
- Migrating a project from tsup to tsdown
- Understanding differences between tsup and tsdown options
- Reviewing or fixing post-migration configuration issues
- Advising users on tsup→tsdown compatibility
Migration Overview
Follow these steps to migrate a tsup project:
- Rename config file: →
- Update imports: →
- Apply option mappings: Rename/transform options per tables below
- Preserve tsup defaults: Explicitly set options that differ (format, clean, dts, target)
- Update package.json: Dependencies, scripts, root config field
- Remove unsupported options: Replace with alternatives where available
- Test build: Run and verify output
Config File Migration
File Rename
Import and Identifier Changes
ts
// Before
import { defineConfig } from 'tsup'
// After
import { defineConfig } from 'tsdown'
Replace all identifiers:
→
,
→
.
Option Mappings
Property Renames
| tsup | tsdown | Notes |
|---|
| | CJS default export handling |
| | Now uses Rolldown/Unplugin plugins |
Deprecated but Compatible
These tsup options still work in tsdown for backward compatibility, but emit deprecation warnings and will be removed in a future version. Migrate them immediately.
| tsup (deprecated) | tsdown (preferred) | Notes |
|---|
| | Also deprecated in tsup itself |
| | Copy static files to output |
| (remove) | Bundle is default behavior |
| | Preserve file structure |
| | Strip prefix |
| | CSS injection |
| (remove) | Default behavior |
| deps: { neverBundle: [...] }
| Moved to deps namespace |
| deps: { alwaysBundle: [...] }
| Moved to deps namespace |
| deps: { skipNodeModulesBundle: true }
| Moved to deps namespace |
Dependency Namespace Moves
Dependencies config moved under
namespace. If both
and
exist, merge into a single
object:
ts
// Before (tsup)
export default defineConfig({
external: ['react'],
noExternal: ['lodash-es'],
})
// After (tsdown)
export default defineConfig({
deps: {
neverBundle: ['react'],
alwaysBundle: ['lodash-es'],
},
})
tsdown also adds
(whitelist of allowed bundled packages) — no tsup equivalent.
Plugin Import Transforms
ts
// Before (tsup - esbuild plugins)
import plugin from 'unplugin-example/esbuild'
// After (tsdown - Rolldown plugins)
import plugin from 'unplugin-example/rolldown'
All
imports should change to
.
For complete before/after examples of every transformation, see guide-option-mappings.md.
Default Value Differences
tsdown changes several defaults from tsup. When migrating, explicitly set these to preserve tsup behavior, then let the user decide which new defaults to adopt.
| Option | tsup Default | tsdown Default | Migration Action |
|---|
| | | Set to preserve |
| | | Set to preserve |
| | Auto-enabled if / in package.json | Set to preserve |
| (none) | Auto-reads from in package.json | Set to preserve |
After migration, suggest the user review these — tsdown's defaults are generally better:
- ESM is the modern standard
- Cleaning output prevents stale files
- Auto DTS from package.json reduces config
- Auto target from engines.node ensures consistency
Unsupported Options
These tsup options have no direct equivalent in tsdown. Remove them and inform the user.
| tsup Option | Status | Alternative |
|---|
| Always enabled | Remove — code splitting cannot be disabled in tsdown |
| Not available | Suggest for Vite DevTools bundle analysis |
| Not supported | Remove — tsdown uses oxc for transformation (built-in) |
| Not supported | Use the option instead |
| Not supported | Remove — no alternative |
| (tsup experimental) | Incompatible | Migrate to Rolldown plugins manually; tsup's plugin API differs from Rolldown's |
Package.json Migration
Scripts
Replace
and
with
in all script commands:
json
// Before
{
"scripts": {
"build": "tsup src/index.ts",
"dev": "tsup --watch"
}
}
// After
{
"scripts": {
"build": "tsdown src/index.ts",
"dev": "tsdown --watch"
}
}
Dependencies
| Location | Action |
|---|
| Rename to |
| Rename to |
optionalDependencies.tsup
| Rename to optionalDependencies.tsdown
|
| Rename to |
peerDependenciesMeta.tsup
| Rename to peerDependenciesMeta.tsdown
|
Root Config Field
If package.json has a root-level
field (inline config), rename to
:
json
// Before
{ "tsup": { "entry": ["src/index.ts"] } }
// After
{ "tsdown": { "entry": ["src/index.ts"] } }
For detailed package.json examples, see guide-package-json.md.
New tsdown Features
After migration, suggest these tsdown-exclusive features to the user:
| Feature | Config | Description |
|---|
| Node protocol | nodeProtocol: true | 'strip'
| Add or strip prefix on built-in imports |
| Workspace | | Build multiple packages in a monorepo |
| Package exports | | Auto-generate field in package.json |
| Package validation | , | Lint package and check type correctness |
| Executable | | Bundle as Node.js standalone executable (SEA) |
| DevTools | | Vite DevTools integration for bundle analysis |
| Hooks | hooks: { 'build:done': ... }
| Lifecycle hooks: , , |
| CSS modules | css: { modules: { ... } }
| Scoped class names for files |
| Glob import | | Support (Vite-style) |
For detailed comparisons, see guide-differences-detailed.md.
References
| Topic | Description | Reference |
|---|
| Option Mappings | Complete before/after for every option transform | guide-option-mappings |
| Detailed Differences | Architecture, features, compatibility comparison | guide-differences-detailed |
| Package.json | Dependency, script, and config field migration | guide-package-json |
Migration Checklist
Use this checklist when performing a migration:
- [ ] Rename tsup.config.* → tsdown.config.*
- [ ] Update import from 'tsup' to 'tsdown'
- [ ] Replace tsup/TSUP identifiers with tsdown/TSDOWN
- [ ] Apply property renames (cjsInterop→cjsDefault, esbuildPlugins→plugins)
- [ ] Migrate deprecated options (publicDir→copy, bundle→unbundle, removeNodeProtocol→nodeProtocol, injectStyle→css.inject)
- [ ] Move external/noExternal/skipNodeModulesBundle into deps namespace
- [ ] Update unplugin imports from /esbuild to /rolldown
- [ ] Set explicit defaults to preserve tsup behavior (format, clean, dts, target)
- [ ] Remove unsupported options (splitting, metafile, swc, etc.)
- [ ] Update package.json scripts (tsup→tsdown)
- [ ] Update package.json dependencies
- [ ] Rename root-level tsup config field if present
- [ ] Run tsdown and verify build output
- [ ] Suggest new tsdown features to the user