---
name: tsdown-migrate
description: Migrate TypeScript library projects from tsup to tsdown. Provides complete option mappings, config transformation rules, default value differences, and unsupported option alternatives so AI agents can intelligently perform migrations.
---
# 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:
1. **Rename config file**: `tsup.config.*` → `tsdown.config.*`
2. **Update imports**: `'tsup'` → `'tsdown'`
3. **Apply option mappings**: Rename/transform options per tables below
4. **Preserve tsup defaults**: Explicitly set options that differ (format, clean, dts, target)
5. **Update package.json**: Dependencies, scripts, root config field
6. **Remove unsupported options**: Replace with alternatives where available
7. **Test build**: Run `tsdown` and verify output
## Config File Migration
### File Rename
| tsup | tsdown |
|------|--------|
| `tsup.config.ts` | `tsdown.config.ts` |
| `tsup.config.cts` | `tsdown.config.cts` |
| `tsup.config.mts` | `tsdown.config.mts` |
| `tsup.config.js` | `tsdown.config.js` |
| `tsup.config.cjs` | `tsdown.config.cjs` |
| `tsup.config.mjs` | `tsdown.config.mjs` |
| `tsup.config.json` | `tsdown.config.json` |
### Import and Identifier Changes
```ts
// Before
import { defineConfig } from 'tsup'
// After
import { defineConfig } from 'tsdown'
```
Replace all identifiers: `tsup` → `tsdown`, `TSUP` → `TSDOWN`.
## Option Mappings
### Property Renames
| tsup | tsdown | Notes |
|------|--------|-------|
| `cjsInterop` | `cjsDefault` | CJS default export handling |
| `esbuildPlugins` | `plugins` | 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 |
|--------------------|--------------------|-------|
| `entryPoints` | `entry` | Also deprecated in tsup itself |
| `publicDir` | `copy` | Copy static files to output |
| `bundle: true` | _(remove)_ | Bundle is default behavior |
| `bundle: false` | `unbundle: true` | Preserve file structure |
| `removeNodeProtocol: true` | `nodeProtocol: 'strip'` | Strip `node:` prefix |
| `injectStyle: true` | `css: { inject: true }` | CSS injection |
| `injectStyle: false` | _(remove)_ | Default behavior |
| `external: [...]` | `deps: { neverBundle: [...] }` | Moved to deps namespace |
| `noExternal: [...]` | `deps: { alwaysBundle: [...] }` | Moved to deps namespace |
| `skipNodeModulesBundle` | `deps: { skipNodeModulesBundle: true }` | Moved to deps namespace |
### Dependency Namespace Moves
Dependencies config moved under `deps` namespace. If both `external` and `noExternal` exist, merge into a single `deps` 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 `deps.onlyBundle` (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 `unplugin-*/esbuild` imports should change to `unplugin-*/rolldown`.
For complete before/after examples of every transformation, see [guide-option-mappings.md](references/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 |
|--------|-------------|----------------|-----------------|
| `format` | `'cjs'` | `'esm'` | Set `format: 'cjs'` to preserve |
| `clean` | `false` | `true` | Set `clean: false` to preserve |
| `dts` | `false` | Auto-enabled if `types`/`typings` in package.json | Set `dts: false` to preserve |
| `target` | _(none)_ | Auto-reads from `engines.node` in package.json | Set `target: false` 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 |
|-------------|--------|-------------|
| `splitting` | Always enabled | Remove — code splitting cannot be disabled in tsdown |
| `metafile` | Not available | Suggest `devtools: true` for Vite DevTools bundle analysis |
| `swc` | Not supported | Remove — tsdown uses oxc for transformation (built-in) |
| `experimentalDts` | Not supported | Use the `dts` option instead |
| `legacyOutput` | Not supported | Remove — no alternative |
| `plugins` (tsup experimental) | Incompatible | Migrate to Rolldown plugins manually; tsup's plugin API differs from Rolldown's |
## Package.json Migration
### Scripts
Replace `tsup` and `tsup-node` with `tsdown` 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 |
|----------|--------|
| `dependencies.tsup` | Rename to `dependencies.tsdown` |
| `devDependencies.tsup` | Rename to `devDependencies.tsdown` |
| `optionalDependencies.tsup` | Rename to `optionalDependencies.tsdown` |
| `peerDependencies.tsup` | Rename to `peerDependencies.tsdown` |
| `peerDependenciesMeta.tsup` | Rename to `peerDependenciesMeta.tsdown` |
### Root Config Field
If package.json has a root-level `tsup` field (inline config), rename to `tsdown`:
```json
// Before
{ "tsup": { "entry": ["src/index.ts"] } }
// After
{ "tsdown": { "entry": ["src/index.ts"] } }
```
For detailed package.json examples, see [guide-package-json.md](references/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 `node:` prefix on built-in imports |
| Workspace | `workspace: 'packages/*'` | Build multiple packages in a monorepo |
| Package exports | `exports: true` | Auto-generate `exports` field in package.json |
| Package validation | `publint: true`, `attw: true` | Lint package and check type correctness |
| Executable | `exe: true` | Bundle as Node.js standalone executable (SEA) |
| DevTools | `devtools: true` | Vite DevTools integration for bundle analysis |
| Hooks | `hooks: { 'build:done': ... }` | Lifecycle hooks: `build:prepare`, `build:before`, `build:done` |
| CSS modules | `css: { modules: { ... } }` | Scoped class names for `.module.css` files |
| Glob import | `globImport: true` | Support `import.meta.glob` (Vite-style) |
For detailed comparisons, see [guide-differences-detailed.md](references/guide-differences-detailed.md).
## References
| Topic | Description | Reference |
|-------|-------------|-----------|
| Option Mappings | Complete before/after for every option transform | [guide-option-mappings](references/guide-option-mappings.md) |
| Detailed Differences | Architecture, features, compatibility comparison | [guide-differences-detailed](references/guide-differences-detailed.md) |
| Package.json | Dependency, script, and config field migration | [guide-package-json](references/guide-package-json.md) |
## 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
```