Upgrading tsdown 0.22 to 0.23
Breaking0.22.14 → 0.23.4Breaking13New8Changed3Fixed20Other1
BreakingUpgrade verdict
12 breaking changes.
In plain terms
- If you build with Node.js 25, you must switch to Node 22.18+, 24.11+, or 26+.
- Old tsup-style config options no longer work; use the new tsdown option names instead.
- Older TypeScript resolution fallbacks are gone; use modern module resolution settings.
- The package validation now runs a lighter ESM-only check by default.
Must act Top 3 of 12 that need code or config changes
Node.js requirement changed in 0.23.0-beta.1: ^22.18.0 || >=24.11.0 → ^22.18.0 || ^24.11.0 || >=26.0.0.
Adds tinyps ^0.5.1.
Drops ansis, tree-kill.
Installs 54 packages in all (was 66).
What you must change
Breaking12
Drops support for Node.js 25; supported versions are ^22.18.0, ^24.11.0, or >=26.0.0.
Removes deprecated tsup compatibility options such as bundle, outExtension, publicDir, removeNodeProtocol, and injectStyle.
bundleoutExtensionpublicDirremoveNodeProtocolinjectStyleDrops the legacy types and typesVersions fields from generated package metadata.
typestypesVersionsChanges the attw default profile from strict to esm-only.
attwprofileRemoves the deprecated deps.onlyAllowBundle option.
deps.onlyAllowBundledeps.onlyBundleDisables resolveDepSubpath by default.
resolveDepSubpathRemoves the deprecated skipNodeModulesBundle option.
skipNodeModulesBundledeps.neverBundleRemoves the dts.cjsReexport option; dual-format builds now generate CJS declarations in a separate pass.
dts.cjsReexportDrops the
types and typesVersions fields.typestypesVersionsRemoves the deprecated deps.onlyAllowBundle option.
deps.onlyAllowBundleRemoves the dts.cjsReexport option.
dts.cjsReexportMakes dts.generator the only way to select the declaration generator.
dts.generatordts.oxcdts.tsgoAPI changes
Generated by DepDelta from published .d.ts files. Not mixed with prose notes.
- added:
export { UserConfigFnContext }
- changed:
function build(inlineConfig?: InlineConfig): Promise<TsdownBundle[]> → function build(inlineConfig?: InlineConfig): Promise<TsdownHandle> - changed:
function buildWithConfigs(configs: ResolvedConfig[], configDeps: Set<string>, _restart: () => void): Promise<TsdownBundle[]> → function buildWithConfigs(configs: ResolvedConfig[], configDeps: Set<string>, rebuild: () => Promise<TsdownHandle>): Promise<TsdownHandle> - added:
export { TsdownHandle } - added:
export { UserConfigFnContext }
- added:
function ShimsPlugin(config: ResolvedConfig, format: NormalizedFormat): Plugin
- removed:
const J: Logger - removed:
const z: string - removed:
export { UnusedOptions as u } - removed:
function W({ pkg, deps: { neverBundle, alwaysBundle: jsAlwaysBundle, onlyBundle, onlyImport, skipNodeModulesBundle, resolveDepSubpath: shouldResolveDepSubpath, dts }, logger, nameLabel, platform }: ResolvedConfig, tsdownBundle: TsdownBundle): Plugin - removed:
function _<T>(moduleName: string): Promise<T> - removed:
function x(config: ResolvedConfig, cjsDts?: boolean, isDualFormat?: boolean): Plugin - removed:
interface F - removed:
interface K extends Pick<DepsConfig, 'neverBundle' | 'skipNodeModulesBundle' | 'resolveDepSubpath'> - removed:
interface M - removed:
interface S<A = any> extends Plugin<A> - removed:
interface V - removed:
interface X extends AsyncDisposable - removed:
interface b - removed:
interface h - removed:
interface k - removed:
interface n extends Options$1 - removed:
interface w extends Omit<Options, 'pack' | 'pkgDir'> - removed:
property A.format: NormalizedFormat - removed:
property A.options: InputOptions - removed:
property A.pkgType?: PackageType - removed:
property E.ignoreRules?: ('no-resolution' | 'untyped-resolution' | 'false-cjs' | 'false-esm' | 'cjs-resolves-to-esm' | 'fallback-condition' | 'cjs-only-exports-default' | 'named-exports' | 'false-export-default' | 'missing-export-equals' | 'unexpected-module-syntax' | 'internal-resolution-error' | (string & {}))[] - removed:
property E.level?: 'error' | 'warn' - removed:
property E.module?: typeof import('@arethetypeswrong/core') - removed:
property E.profile?: 'strict' | 'node16' | 'esm-only' - removed:
property F.hooks: Hookable<TsdownHooks> - removed:
property F.options: ResolvedConfig - removed:
property H.clean?: boolean - removed:
property H.ui?: boolean | Partial<StartOptions> - removed:
property I.buildOptions: BuildOptions - removed:
property K.alwaysBundle?: NoExternalFn - removed:
property K.dts: Pick<ResolvedDepsConfig, 'alwaysBundle' | 'neverBundle'> - removed:
property K.onlyBundle?: Array<string | RegExp> | false - removed:
property K.onlyImport?: Array<string | RegExp> - removed:
property L.'build:before': (ctx: BuildContext & RolldownContext) => void | Promise<void> - removed:
property L.'build:done': (ctx: BuildContext & { chunks: RolldownChunk[] }) => void | Promise<void> - removed:
property L.'build:prepare': (ctx: BuildContext) => void | Promise<void> - removed:
property M.dts?: string - removed:
property M.js?: string - removed:
property N.packageJsonPath: string - removed:
property R.fileName?: string | ((chunk: RolldownChunk) => string) - removed:
property R.outDir?: string - removed:
property R.seaConfig?: Omit<SeaConfig, 'main' | 'output' | 'mainFormat'> - removed:
property S.tsdownConfig?: (config: UserConfig, inlineConfig: InlineConfig) => Awaitable<UserConfig | void | null> - removed:
property S.tsdownConfigResolved?: (resolvedConfig: ResolvedConfig) => Awaitable<void> - removed:
property T.all?: boolean - removed:
property T.bin?: boolean | string | Record<string, string> - removed:
property T.customExports?: Record<string, any> | ((exports: Record<string, any>, context: { pkg: PackageJson; chunks: ChunksByFormat; isPublish: boolean }) => Awaitable<Record<string, any>>) - removed:
property T.devExports?: boolean | string - removed:
property T.exclude?: (RegExp | string)[] - removed:
property T.extensions?: boolean - removed:
property T.inlinedDependencies?: boolean - removed:
property T.legacy?: boolean - removed:
property T.packageJson?: boolean - removed:
property U.alwaysBundle?: Arrayable<string | RegExp> | NoExternalFn - removed:
property U.dts?: Pick<DepsConfig, 'alwaysBundle' | 'neverBundle'> - removed:
property U.neverBundle?: true | ExternalOption - removed:
property U.onlyAllowBundle?: Arrayable<string | RegExp> | false - removed:
property U.onlyBundle?: Arrayable<string | RegExp> | false - removed:
property U.onlyImport?: Arrayable<string | RegExp> - removed:
property U.resolveDepSubpath?: boolean - removed:
property U.skipNodeModulesBundle?: boolean - removed:
property V.assets?: Record<string, string> - removed:
property V.disableExperimentalSEAWarning?: boolean - removed:
property V.execArgv?: string[] - removed:
property V.execArgvExtension?: 'none' | 'env' | 'cli' - removed:
property V.executable?: string - removed:
property V.main?: string - removed:
property V.mainFormat?: 'commonjs' | 'module' - removed:
property V.output?: string - removed:
property V.useCodeCache?: boolean - removed:
property V.useSnapshot?: boolean - removed:
property X.chunks: RolldownChunk[] - removed:
property X.config: ResolvedConfig - removed:
property X.inlinedDeps: Map<string, Set<string>> - removed:
property Z.flatten?: boolean - removed:
property Z.from: string | string[] - removed:
property Z.rename?: string | ((name: string, extension: string, fullPath: string) => string) - removed:
property Z.to?: string - removed:
property Z.verbose?: boolean - removed:
property b.brotli?: boolean - removed:
property b.gzip?: boolean - removed:
property b.maxCompressSize?: number - removed:
property d.bundle?: boolean - removed:
property d.injectStyle?: boolean - removed:
property d.inlineOnly?: Arrayable<string | RegExp> | false - removed:
property d.outExtension?: OutExtensionFactory - removed:
property d.publicDir?: CopyOptions | CopyOptionsFn - removed:
property d.removeNodeProtocol?: boolean - removed:
property d.skipNodeModulesBundle?: boolean - removed:
property h.config?: boolean | string - removed:
property h.exclude?: Arrayable<string> - removed:
property h.include?: 'auto' | (string & {}) | string[] - removed:
property k.css?: string - removed:
property k.dts?: string - removed:
property k.js?: string - removed:
property n.cjsReexport?: boolean - removed:
property q.clearScreen: (type: LogType) => void - removed:
property q.error: (...args: any[]) => void - removed:
property q.info: (...args: any[]) => void - removed:
property q.level: LogLevel - removed:
property q.options?: LoggerOptions - removed:
property q.success: (...args: any[]) => void - removed:
property q.warn: (...args: any[]) => void - removed:
property q.warnOnce: (...args: any[]) => void - removed:
property w.module?: [typeof import('publint'), typeof import('publint/utils')] - removed:
type $ = (options: ResolvedConfig) => Awaitable<CopyOptions> - removed:
type C<A = any> = Awaitable<TsdownPlugin<A> | RolldownPlugin<A> | { name: string } | undefined | null | void | false | TsdownPluginOption<A>[]> - removed:
type D = ChunkAddonObject | ChunkAddonFunction | string - removed:
type G = (id: string, importer: string | undefined) => boolean | null | undefined | void - removed:
type P = 'module' | 'commonjs' | undefined - removed:
type Q = Arrayable<string | CopyEntry> - removed:
type Y = (OutputChunk | OutputAsset) & { outDir: string } - removed:
type g = <T>(task: () => Promise<T>) => Promise<T> - removed:
type j = (context: OutExtensionContext) => OutExtensionObject | undefined - removed:
type m<T> = boolean | undefined | CIOption | (T & { enabled?: boolean | CIOption }) - changed:
const B: SemVer → const B: string - changed:
function v<T extends string>(arr: T[]): T[] → function v<T>(moduleName: string): Promise<T> - changed:
function y<T>(val: T | T[] | null | undefined, defaultValue?: T): T[] → function y<T extends string>(arr: T[]): T[] - changed:
interface E extends CheckPackageOptions → interface E - changed:
interface H extends NonNullable<InputOptions['devtools']> → interface H - changed:
interface N extends PackageJson → interface N - changed:
interface R extends ExeExtensionOptions → interface R - changed:
interface T → interface T extends Omit<Options, 'pack' | 'pkgDir'> - changed:
interface U → interface U extends NonNullable<InputOptions['devtools']> - changed:
interface Z → interface Z extends AsyncDisposable - changed:
interface q → interface q extends Pick<DepsConfig, 'neverBundle' | 'resolveDepSubpath'> - changed:
property d.envFile?: string → property d.envFile?: string | string[] - changed:
type O = (ctx: { format: Format; fileName: string }) => ChunkAddonObject | string | undefined → type O = ChunkAddonObject | ChunkAddonFunction | string - changed:
type et<T> = T | T[] → type et = Arrayable<string | CopyEntry> - changed:
type nt<T, U> = Omit<T, keyof U> & U → type nt<T> = T | T[] - changed:
type o = Overwrite<MarkPartial<Omit<UserConfig, 'workspace' | 'fromVite' | 'publicDir' | 'bundle' | 'injectStyle' | 'removeNodeProtocol' | 'outExtension' | 'external' |… → type o = Overwrite<MarkPartial<Omit<UserConfig, 'workspace' | 'fromVite' | 'external' | 'noExternal' | 'logLevel' | 'failOnWarn' | 'suppressWarnings' | 'customLogger' |… - changed:
type p = (inlineConfig: InlineConfig, context: { ci: boolean; rootConfig?: UserConfig }) => Awaitable<Arrayable<UserConfig>> → type p = (inlineConfig: InlineConfig, context: UserConfigFnContext) => Awaitable<Arrayable<UserConfig>> - changed:
type tt<T, K extends keyof T> = Omit<Required<T>, K> & Partial<Pick<T, K>> → type tt = (options: ResolvedConfig) => Awaitable<CopyOptions> - added:
const V: SemVer - added:
const Y: Logger - added:
export { DtsOptions as n } - added:
function G({ pkg, deps: { neverBundle, alwaysBundle: jsAlwaysBundle, onlyBundle, onlyImport, resolveDepSubpath: shouldResolveDepSubpath, dts }, logger, nameLabel, platform }: ResolvedConfig, tsdownBundle: TsdownBundle): Plugin - added:
function S(config: ResolvedConfig, cjsDts?: boolean, isDualFormat?: boolean): Plugin - added:
function b<T>(val: T | T[] | null | undefined, defaultValue?: T): T[] - added:
interface $ - added:
interface C<A = any> extends Plugin<A> - added:
interface D extends CheckPackageOptions - added:
interface J - added:
interface P extends PackageJson - added:
interface Q - added:
interface W - added:
interface g - added:
interface j - added:
interface m - added:
interface x - added:
interface z extends ExeExtensionOptions - added:
property $.flatten?: boolean - added:
property $.from: string | string[] - added:
property $.rename?: string | ((name: string, extension: string, fullPath: string) => string) - added:
property $.to?: string - added:
property $.verbose?: boolean - added:
property A.css?: string - added:
property A.dts?: string - added:
property A.js?: string - added:
property C.tsdownConfig?: (config: UserConfig, inlineConfig: InlineConfig) => Awaitable<UserConfig | void | null> - added:
property C.tsdownConfigResolved?: (resolvedConfig: ResolvedConfig) => Awaitable<void> - added:
property D.ignoreRules?: ('no-resolution' | 'untyped-resolution' | 'false-cjs' | 'false-esm' | 'cjs-resolves-to-esm' | 'fallback-condition' | 'cjs-only-exports-default' | 'named-exports' | 'false-export-default' | 'missing-export-equals' | 'unexpected-module-syntax' | 'internal-resolution-error' | (string & {}))[] - added:
property D.level?: 'error' | 'warn' - added:
property D.module?: typeof import('@arethetypeswrong/core') - added:
property D.profile?: 'strict' | 'node16' | 'esm-only' - added:
property E.all?: boolean - added:
property E.bin?: boolean | string | Record<string, string> - added:
property E.customExports?: Record<string, any> | ((exports: Record<string, any>, context: { pkg: PackageJson; chunks: ChunksByFormat; isPublish: boolean }) => Awaitable<Record<string, any>>) - added:
property E.devExports?: boolean | string - added:
property E.exclude?: (RegExp | string)[] - added:
property E.extensions?: boolean - added:
property E.inlinedDependencies?: boolean - added:
property E.legacy?: boolean - added:
property E.packageJson?: boolean - added:
property H.assets?: Record<string, string> - added:
property H.disableExperimentalSEAWarning?: boolean - added:
property H.execArgv?: string[] - added:
property H.execArgvExtension?: 'none' | 'env' | 'cli' - added:
property H.executable?: string - added:
property H.main?: string - added:
property H.mainFormat?: 'commonjs' | 'module' - added:
property H.output?: string - added:
property H.useCodeCache?: boolean - added:
property H.useSnapshot?: boolean - added:
property I.hooks: Hookable<TsdownHooks> - added:
property I.options: ResolvedConfig - added:
property J.clearScreen: (type: LogType) => void - added:
property J.error: (...args: any[]) => void - added:
property J.info: (...args: any[]) => void - added:
property J.level: LogLevel - added:
property J.options?: LoggerOptions - added:
property J.success: (...args: any[]) => void - added:
property J.warn: (...args: any[]) => void - added:
property J.warnOnce: (...args: any[]) => void - added:
property L.buildOptions: BuildOptions - added:
property N.dts?: string - added:
property N.js?: string - added:
property P.packageJsonPath: string - added:
property Q.bundles: TsdownBundle[] - added:
property Q.watch: { restart: () => Promise<TsdownHandle>; close: () => Promise<void> } - added:
property R.'build:before': (ctx: BuildContext & RolldownContext) => void | Promise<void> - added:
property R.'build:done': (ctx: BuildContext & { chunks: RolldownChunk[] }) => void | Promise<void> - added:
property R.'build:prepare': (ctx: BuildContext) => void | Promise<void> - added:
property T.module?: [typeof import('publint'), typeof import('publint/utils')] - added:
property U.clean?: boolean - added:
property U.ui?: boolean | Partial<StartOptions> - added:
property W.alwaysBundle?: Arrayable<string | RegExp> | NoExternalFn - added:
property W.dts?: Pick<DepsConfig, 'alwaysBundle' | 'neverBundle'> - added:
property W.neverBundle?: true | ExternalOption - added:
property W.onlyBundle?: Arrayable<string | RegExp> | false - added:
property W.onlyImport?: Arrayable<string | RegExp> - added:
property W.resolveDepSubpath?: boolean - added:
property Z.chunks: RolldownChunk[] - added:
property Z.config: ResolvedConfig - added:
property Z.inlinedDeps: Map<string, Set<string>> - added:
property g.config?: boolean | string - added:
property g.exclude?: Arrayable<string> - added:
property g.include?: 'auto' | (string & {}) | string[] - added:
property j.format: NormalizedFormat - added:
property j.options: InputOptions - added:
property j.pkgType?: PackageType - added:
property m.ci: boolean - added:
property m.rootConfig?: UserConfig - added:
property m.watch: TsdownHandle['watch'] - added:
property q.alwaysBundle?: NoExternalFn - added:
property q.dts: Pick<ResolvedDepsConfig, 'alwaysBundle' | 'neverBundle'> - added:
property q.onlyBundle?: Array<string | RegExp> | false - added:
property q.onlyImport?: Array<string | RegExp> - added:
property x.brotli?: boolean - added:
property x.gzip?: boolean - added:
property x.maxCompressSize?: number - added:
property x.summary?: boolean - added:
property z.fileName?: string | ((chunk: RolldownChunk) => string) - added:
property z.outDir?: string - added:
property z.seaConfig?: Omit<SeaConfig, 'main' | 'output' | 'mainFormat'> - added:
type F = 'module' | 'commonjs' | undefined - added:
type K = (id: string, importer: string | undefined) => boolean | null | undefined | void - added:
type M = (context: OutExtensionContext) => OutExtensionObject | undefined - added:
type X = (OutputChunk | OutputAsset) & { outDir: string } - added:
type _ = <T>(task: () => Promise<T>) => Promise<T> - added:
type h<T> = boolean | undefined | CIOption | (T & { enabled?: boolean | CIOption }) - added:
type it<T, U> = Omit<T, keyof U> & U - added:
type k = (ctx: { format: Format; fileName: string }) => ChunkAddonObject | string | undefined - added:
type rt<T, K extends keyof T> = Omit<Required<T>, K> & Partial<Pick<T, K>> - added:
type u = import('unplugin-unused').Options - added:
type w<A = any> = Awaitable<TsdownPlugin<A> | RolldownPlugin<A> | { name: string } | undefined | null | void | false | TsdownPluginOption<A>[]>