Files
agent-skills/skills/tsdown/references/advanced-programmatic.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

5.9 KiB

Programmatic Usage

Use tsdown from JavaScript/TypeScript code.

Overview

tsdown can be imported and used programmatically in your Node.js scripts, custom build tools, or automation workflows.

Basic Usage

Simple Build

import { build } from 'tsdown'

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
})

With Options

import { build } from 'tsdown'

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  outDir: 'dist',
  dts: true,
  minify: true,
  sourcemap: true,
  clean: true,
})

API Reference

build()

Main function to run a build.

import { build } from 'tsdown'

await build(options)

Parameters:

  • options - Build configuration object (same as config file)

Returns:

  • Promise<void> - Resolves when build completes

Throws:

  • Build errors if compilation fails

Configuration Object

All config file options are available:

import { build, defineConfig } from 'tsdown'

const config = defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  minify: true,
  sourcemap: true,
  external: ['react', 'react-dom'],
  plugins: [/* plugins */],
  hooks: {
    'build:done': async () => {
      console.log('Build complete!')
    },
  },
})

await build(config)

See Config Reference for all options.

Common Patterns

Custom Build Script

// scripts/build.ts
import { build } from 'tsdown'

async function main() {
  console.log('Building library...')

  await build({
    entry: ['src/index.ts'],
    format: ['esm', 'cjs'],
    dts: true,
    clean: true,
  })

  console.log('Build complete!')
}

main().catch(console.error)

Run with:

tsx scripts/build.ts

Multiple Builds

import { build } from 'tsdown'

// Build main library
await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  outDir: 'dist',
  dts: true,
})

// Build CLI tool
await build({
  entry: ['src/cli.ts'],
  format: ['esm'],
  outDir: 'dist/bin',
  platform: 'node',
  shims: true,
})

Conditional Build

import { build } from 'tsdown'

const isDev = process.env.NODE_ENV === 'development'

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  minify: !isDev,
  sourcemap: isDev,
  clean: !isDev,
})

With Error Handling

import { build } from 'tsdown'

try {
  await build({
    entry: ['src/index.ts'],
    format: ['esm', 'cjs'],
    dts: true,
  })
  console.log('✅ Build successful')
} catch (error) {
  console.error('❌ Build failed:', error)
  process.exit(1)
}

Automated Workflow

import { build } from 'tsdown'
import { execSync } from 'child_process'

async function release() {
  // Clean
  console.log('Cleaning...')
  execSync('rm -rf dist')

  // Build
  console.log('Building...')
  await build({
    entry: ['src/index.ts'],
    format: ['esm', 'cjs'],
    dts: true,
    minify: true,
  })

  // Test
  console.log('Testing...')
  execSync('npm test')

  // Publish
  console.log('Publishing...')
  execSync('npm publish')
}

release().catch(console.error)

Build with Post-Processing

import { build } from 'tsdown'
import { copyFileSync } from 'fs'

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  hooks: {
    'build:done': async () => {
      // Copy additional files
      copyFileSync('README.md', 'dist/README.md')
      copyFileSync('LICENSE', 'dist/LICENSE')
      console.log('Copied additional files')
    },
  },
})

Watch Mode

Unfortunately, watch mode is not directly exposed in the programmatic API. Use the CLI for watch mode:

// Use CLI for watch mode
import { spawn } from 'child_process'

spawn('tsdown', ['--watch'], {
  stdio: 'inherit',
  shell: true,
})

Integration Examples

With Task Runner

// gulpfile.js
import { build } from 'tsdown'
import gulp from 'gulp'

gulp.task('build', async () => {
  await build({
    entry: ['src/index.ts'],
    format: ['esm', 'cjs'],
    dts: true,
  })
})

gulp.task('watch', () => {
  return gulp.watch('src/**/*.ts', gulp.series('build'))
})

With Custom CLI

// scripts/cli.ts
import { build } from 'tsdown'
import { Command } from 'commander'

const program = new Command()

program
  .command('build')
  .option('--prod', 'Production build')
  .action(async (options) => {
    await build({
      entry: ['src/index.ts'],
      format: ['esm', 'cjs'],
      minify: options.prod,
      sourcemap: !options.prod,
    })
  })

program.parse()

With CI/CD

// .github/scripts/build.ts
import { build } from 'tsdown'

const isCI = process.env.CI === 'true'

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  minify: isCI,
  clean: true,
})

// Upload to artifact storage
if (isCI) {
  // Upload dist/ to S3, etc.
}

TypeScript Support

// scripts/build.ts
import { build, type UserConfig } from 'tsdown'

const config: UserConfig = {
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
}

await build(config)

Tips

  1. Use TypeScript for type safety
  2. Handle errors properly
  3. Use hooks for custom logic
  4. Log progress for visibility
  5. Use CLI for watch mode
  6. Exit on error in scripts

Troubleshooting

Import Errors

Ensure tsdown is installed:

pnpm add -D tsdown

Type Errors

Import types:

import type { UserConfig } from 'tsdown'

Build Fails Silently

Add error handling:

try {
  await build(config)
} catch (error) {
  console.error(error)
  process.exit(1)
}

Options Not Working

Check spelling and types:

// ✅ Correct
{ format: ['esm', 'cjs'] }

// ❌ Wrong
{ formats: ['esm', 'cjs'] }