Skip to content

Copy Files

The copy option copies static files and directories into your build output. It is useful for assets that should be distributed without being processed by the bundler, such as images, fonts, and license files.

Using the CLI

Pass a directory to --copy to copy it into the output directory:

bash
tsdown --copy public

With the default outDir of dist, a file at public/favicon.svg is copied to dist/public/favicon.svg.

Using the Config File

The simplest configuration is a path or glob pattern:

tsdown.config.ts
ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  copy: 'public',
})

You can provide multiple paths, glob patterns, or object entries in an array:

tsdown.config.ts
ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  copy: [
    'LICENSE',
    {
      from: ['public/**/*', '!public/**/*.map'],
      to: 'dist/assets',
      flatten: false,
    },
  ],
})

Glob patterns support negation with a leading !. In this example, files below public are copied to dist/assets with their relative directory structure preserved, while source map files are excluded.

NOTE

Relative source and destination paths are resolved from the project root (cwd), not from outDir.

Object Options

Object entries support the following properties:

PropertyTypeDefaultDescription
fromstring | string[]RequiredA source path or glob pattern. An array can include negated patterns.
tostringoutDirThe destination path, resolved from the project root.
flattenbooleantruePlaces matched files directly in to. Set to false to preserve the directory structure below the first segment.
renamestring | ((name, extension, fullPath) => string)Changes the destination name. The callback receives the extension without a leading dot and the absolute path.
verbosebooleanfalseLogs each copied source and destination.

Preserve Directory Structure

Glob matches are flattened into the destination by default. Set flatten: false to keep their relative structure:

tsdown.config.ts
ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  copy: {
    from: 'assets/**/*',
    to: 'dist/public',
    flatten: false,
  },
})

For example, assets/fonts/inter.woff2 is copied to dist/public/fonts/inter.woff2.

Rename Copied Items

Use a string or a callback to rename copied items:

tsdown.config.ts
ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  copy: [
    {
      from: 'src/file.txt',
      to: 'dist',
      rename: 'file.md',
    },
    {
      from: 'src/file.txt',
      to: 'dist',
      rename: (name, extension) => `${name}-renamed.${extension}`,
    },
  ],
})

This creates dist/file.md and dist/file-renamed.txt.

Dynamic Configuration

copy can also be a synchronous or asynchronous callback. It receives the resolved tsdown configuration and returns the same string, object, or array forms:

tsdown.config.ts
ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  copy: ({ outDir }) => ({
    from: ['assets/**/*', '!assets/**/*.map'],
    to: `${outDir}/assets`,
    flatten: false,
  }),
})

Build and Watch Behavior

Copying runs after the bundle output is produced. Static files are copied without passing through Rolldown transforms. A top-level copy option runs only once for a multi-format build; a format-specific override can define copy again for that format.

In watch mode, matched source files are watched as build dependencies. Changing one triggers a rebuild and copies the current files again.

Released under the MIT License.