Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Bundle TypeScript and JavaScript libraries with blazing-fast speed powered by Rolldown. Use when building libraries, generating type declarations, bundling for multiple formats, or migrating from tsup.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 400% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 88% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 189% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 244% | 0% |
Blazing-fast bundler for TypeScript/JavaScript libraries powered by Rolldown and Oxc.
tsdown requires Node.js 22.18.0 or higher to run (build-time only). However, the bundled output can target much lower Node.js versions via the target option, so libraries built with tsdown are not locked to Node.js 22+ at runtime.
If your package needs to support Node.js 18 / 20:
target: 'node18' or target: 'node20').bash# Install pnpm add -D tsdown # Basic usage npx tsdown # With config file npx tsdown --config tsdown.config.ts # Watch mode npx tsdown --watch # Migrate from tsup npx tsdown-migrate
tsimport { defineConfig } from 'tsdown' export default defineConfig({ entry: ['./src/index.ts'], format: ['esm', 'cjs'], dts: true, clean: true, })
| Topic | Description | Reference | |-------|-------------|-----------| | Getting Started | Installation, first bundle, CLI basics | guide-getting-started | | Configuration File | Config file formats, multiple configs, workspace | option-config-file | | CLI Reference | All CLI commands and options | reference-cli | | Migrate from tsup | Migration guide and compatibility notes | guide-migrate-from-tsup | | Plugins | Rolldown, Rollup, Unplugin support | advanced-plugins |
> For comprehensive migration assistance with complete option mappings, install the dedicated tsdown-migrate skill: npx skills add rolldown/tsdown --skill tsdown-migrate | Hooks | Lifecycle hooks for custom logic | advanced-hooks | | Programmatic API | Build from Node.js scripts | advanced-programmatic | | Rolldown Options | Pass options directly to Rolldown | advanced-rolldown-options | | CI Environment | CI detection, 'ci-only' / 'local-only' values | advanced-ci |
| Option | Usage | Reference | |--------|-------|-----------| | Entry points | entry: ['src/*.ts', '!**/*.test.ts'] | option-entry | | Output formats | format: ['esm', 'cjs', 'iife', 'umd'] | option-output-format | | Output directory | outDir: 'dist', outExtensions | option-output-directory | | Type declarations | dts: true, dts: { sourcemap, compilerOptions, vue } | option-dts | | Target environment | target: 'es2020', target: 'esnext' | option-target | | Platform | platform: 'node', platform: 'browser' | option-platform | | Tree shaking | treeshake: true, custom options | option-tree-shaking | | Minification | minify: true, minify: 'dce-only' | option-minification | | Source maps | sourcemap: true, 'inline', 'hidden' | option-sourcemap | | Watch mode | watch: true, watch options | option-watch-mode | | Cleaning | clean: true, clean patterns | option-cleaning | | Log level | logLevel: 'silent', failOnWarn: false | option-log-level |
| Feature | Usage | Reference | |---------|-------|-----------| | Never bundle | deps: { neverBundle: ['react', /^@myorg\//] } | option-dependencies | | Always bundle | deps: { alwaysBundle: ['dep-to-bundle'] } | option-dependencies | | Only bundle | deps: { onlyBundle: ['cac', 'bumpp'] } - Whitelist | option-dependencies | | Skip node_modules | deps: { skipNodeModulesBundle: true } | option-dependencies | | Auto external | Automatic dependency/peer/optional externalization | option-dependencies |
| Feature | Usage | Reference | |---------|-------|-----------| | Shims | shims: true - Add ESM/CJS compatibility | option-shims | | CJS default | cjsDefault: true (default) / false | option-cjs-default | | Package exports | exports: true - Generate exports field | option-package-exports | | CSS handling | experimental] css: { ... } — full pipeline with preprocessors, Lightning CSS, PostCSS, CSS modules, code splitting; requires @tsdown/css | option-css | | CSS modules | css: { modules: { localsConvention: 'camelCase' } } — scoped class names for .module.css files | option-css | | CSS inject | css: { inject: true } — preserve CSS imports in JS output | option-css | | Unbundle mode | unbundle: true - Preserve directory structure | option-unbundle | | Root directory | root: 'src' - Control output directory mapping | option-root | | Executable | experimental] exe: true - Bundle as standalone executable, cross-platform via @tsdown/exe | option-exe | | Package validation | publint: true, attw: true - Validate package | option-lint |
| Framework | Guide | Reference | |-----------|-------|-----------| | React | JSX transform, React Compiler | recipe-react | | Vue | SFC support, JSX | recipe-vue | | Solid | SolidJS JSX transform | recipe-solid | | Svelte | Svelte component libraries (source distribution recommended) | recipe-svelte | | WASM | WebAssembly modules via rolldown-plugin-wasm | recipe-wasm |
tsexport default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, clean: true, })
tsexport default defineConfig({ entry: { index: 'src/index.ts', utils: 'src/utils.ts', cli: 'src/cli.ts', }, format: ['esm', 'cjs'], dts: true, })
tsexport default defineConfig({ entry: ['src/index.ts'], format: ['iife'], globalName: 'MyLib', platform: 'browser', minify: true, })
tsexport default defineConfig({ entry: ['src/index.tsx'], format: ['esm', 'cjs'], dts: true, deps: { neverBundle: ['react', 'react-dom'], }, inputOptions: { jsx: { runtime: 'automatic' }, }, })
tsexport default defineConfig({ entry: ['src/**/*.ts', '!**/*.test.ts'], unbundle: true, // Preserve file structure format: ['esm'], dts: true, })
tsexport default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, failOnWarn: 'ci-only', // opt-in: fail on warnings in CI publint: 'ci-only', attw: 'ci-only', })
tsimport { wasm } from 'rolldown-plugin-wasm' import { defineConfig } from 'tsdown' export default defineConfig({ entry: ['src/index.ts'], plugins: [wasm()], })
tsexport default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, target: 'chrome100', css: { preprocessorOptions: { scss: { additionalData: `@use "src/styles/variables" as *;`, }, }, }, })
tsexport default defineConfig({ entry: ['src/cli.ts'], exe: true, })
@tsdown/exe)tsexport default defineConfig({ entry: ['src/cli.ts'], exe: { targets: [ { platform: 'linux', arch: 'x64', nodeVersion: '25.7.0' }, { platform: 'darwin', arch: 'arm64', nodeVersion: '25.7.0' }, { platform: 'win', arch: 'x64', nodeVersion: '25.7.0' }, ], }, })
tsexport default defineConfig({ entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, hooks: { 'build:before': async (context) => { console.log('Building...') }, 'build:done': async (context) => { console.log('Build complete!') }, }, })
Export an array for multiple build configurations:
tsexport default defineConfig([ { entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, }, { entry: ['src/cli.ts'], format: ['esm'], platform: 'node', }, ])
Use functions for dynamic configuration:
tsexport default defineConfig((options) => { const isDev = options.watch return { entry: ['src/index.ts'], format: ['esm', 'cjs'], minify: !isDev, sourcemap: isDev, } })
Use glob patterns to build multiple packages:
tsexport default defineConfig({ workspace: 'packages/*', entry: ['src/index.ts'], format: ['esm', 'cjs'], dts: true, })
bash# Basic commands tsdown # Build once tsdown --watch # Watch mode tsdown --config custom.ts # Custom config npx tsdown-migrate # Migrate from tsup # Output options tsdown --format esm,cjs # Multiple formats tsdown -d lib # Custom output directory (--out-dir) tsdown --minify # Enable minification tsdown --dts # Generate declarations tsdown --exe # Bundle as standalone executable tsdown --unbundle # Bundleless mode # Entry options tsdown src/index.ts # Single entry tsdown src/*.ts # Glob patterns tsdown src/a.ts src/b.ts # Multiple entries # Workspace / Monorepo tsdown -W # Enable workspace mode tsdown -W -F my-package # Filter specific package tsdown --filter /^pkg-/ # Filter by regex # Development tsdown --watch # Watch mode tsdown --sourcemap # Generate source maps tsdown --clean # Clean output directory tsdown --from-vite # Reuse Vite config tsdown --tsconfig tsconfig.build.json # Custom tsconfig
ts { dts: true }
ts { deps: { neverBundle: [/^react/, /^@myorg\//] } }
ts { treeshake: true }
ts { minify: true }
ts { shims: true } // Adds __dirname, __filename, etc.
ts { exports: true } // Creates proper exports field
bash tsdown --watch
ts { unbundle: true } // Keep directory structure
ts { publint: 'ci-only', attw: 'ci-only' }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 4,671 | 3,899 | -17% | 1 | 1 | 0% | 899 | 4,499 | +400% | 0 | 0 | — |
case-02 | fail→pass | 15,102 | 5,441 | -64% | 1 | 1 | 0% | 2,856 | 4,839 | +69% | 0 | 0 | — |
case-03 | fail→pass | 13,630 | 7,374 | -46% | 1 | 1 | 0% | 2,816 | 5,293 | +88% | 0 | 0 | — |
case-04 | fail→pass | 7,799 | 15,172 | +95% | 1 | 1 | 0% | 1,499 | 4,328 | +189% | 0 | 0 | — |
case-05 | fail→pass | 6,674 | 3,413 | -49% | 1 | 1 | 0% | 1,214 | 4,172 | +244% | 0 | 0 | — |
case-06 | fail→pass | 11,764 | 4,166 | -65% | 1 | 1 | 0% | 2,249 | 4,505 | +100% | 0 | 0 | — |
case-07 | fail→pass | 17,339 | 2,450 | -86% | 1 | 1 | 0% | 2,271 | 4,224 | +86% | 0 | 0 | — |
case-08 | fail→pass | 22,116 | 2,364 | -89% | 1 | 1 | 0% | 3,999 | 4,107 | +3% | 0 | 0 | — |
case-09 | pass→pass | 6,170 | 2,855 | -54% | 1 | 1 | 0% | 1,066 | 4,256 | +299% | 0 | 0 | — |
case-10 | fail→pass | 10,508 | 2,964 | -72% | 1 | 1 | 0% | 1,995 | 4,216 | +111% | 0 | 0 | — |
case-11 | fail→pass | 10,967 | 10,551 | -4% | 1 | 1 | 0% | 2,235 | 4,747 | +112% | 0 | 0 | — |
case-12 | pass→pass | 8,015 | 3,255 | -59% | 1 | 1 | 0% | 1,576 | 4,306 | +173% | 0 | 0 | — |
case-13 | fail→pass | 10,757 | 3,462 | -68% | 1 | 1 | 0% | 1,938 | 4,412 | +128% | 0 | 0 | — |
case-14 | fail→pass | 12,835 | 2,908 | -77% | 1 | 1 | 0% | 2,532 | 4,267 | +69% | 0 | 0 | — |
case-15 | fail→pass | 7,163 | 3,060 | -57% | 1 | 1 | 0% | 1,409 | 4,361 | +210% | 0 | 0 | — |
case-16 | pass→pass | 12,535 | 2,194 | -82% | 1 | 1 | 0% | 2,327 | 4,076 | +75% | 0 | 0 | — |
case-17 | pass→pass | 10,676 | 4,975 | -53% | 1 | 1 | 0% | 1,988 | 4,325 | +118% | 0 | 0 | — |
case-18 | fail→pass | 5,643 | 2,247 | -60% | 1 | 1 | 0% | 1,002 | 4,119 | +311% | 0 | 0 | — |
case-19 | fail→pass | 10,285 | 2,302 | -78% | 1 | 1 | 0% | 1,975 | 4,003 | +103% | 0 | 0 | — |
case-20 | pass→pass | 10,268 | 5,646 | -45% | 1 | 1 | 0% | 1,617 | 4,842 | +199% | 0 | 0 | — |
case-21 | pass→pass | 7,513 | 5,040 | -33% | 1 | 1 | 0% | 1,315 | 4,651 | +254% | 0 | 0 | — |
case-22 | pass→pass | 6,751 | 5,374 | -20% | 1 | 1 | 0% | 1,368 | 4,765 | +248% | 0 | 0 | — |
case-23 | pass→pass | 3,822 | 3,090 | -19% | 1 | 1 | 0% | 722 | 4,295 | +495% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +65 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +50% |
Other measured skills in the registry, with their headline benchmark lift.