This content originally appeared on DEV Community and was authored by Sean Boult
There comes a time when you have to dual publish ESM (ECMAScript) and CJS (CommonJS) for your TypeScript projects. This guide should walk you through the steps to get this working properly with tsdown.
NOTE: if you are using tsup there is a codemod provided by tsdown to migrate.
tsdown setup
First let's install tsdown with your favorite package manager, in this case I'll be using pnpm.
pnpm i -D tsdown
Now we can create the tsdown.config.ts file that will have our configuration.
import { defineConfig } from "tsdown";
export default defineConfig([
{
entry: ["src/index.ts"],
format: ["esm", "cjs"],
dts: true,
sourcemap: true,
clean: true,
outDir: "dist"
}
]);
package json setup
It's important to get these right otherwise types will fail to resolve in every scenario.
Add the following to your package.json file.
{
// ...
"files": [
"dist"
],
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
}
// ...
}
validation
We can us the are the types wrong CLI to interrogate the output and ensure type resolution is working in all scenarios.
npx -y @arethetypeswrong/cli --pack .
Which should yield something like this if all goes well.
No problems found ๐
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ "tsdown-dual-publish-esm-cjs" โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node10 โ ๐ข โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node16 (from CJS) โ ๐ข (CJS) โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node16 (from ESM) โ ๐ข (ESM) โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ bundler โ ๐ข โ
โโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Demo
Here is a simple demo I've create to show what we've seen here.
tsdown-dual-publish-esm-cjs
If you want to migrate from tsup this is a repo to follow.
pnpm i
pnpm test
What the ouput of test looks like.
> tsdown
โน tsdown v0.14.2 powered by rolldown v1.0.0-beta.34
โน Using tsdown config: /Users/hacksore/code/tsdown-dual-publish-esm-cjs/tsdown.config.ts
โน entry: src/index.ts
โน tsconfig: tsconfig.json
โน Build start
โน Cleaning 4 files
โน [CJS] dist/index.cjs 0.10 kB โ gzip: 0.11 kB
โน [CJS] 1 files, total: 0.10 kB
โน [CJS] dist/index.d.cts 0.09 kB โ gzip: 0.10 kB
โน [CJS] 1 files, total: 0.09 kB
โน [ESM] dist/index.js 0.10 kB โ gzip: 0.11 kB
โน [ESM] dist/index.d.ts 0.09 kB โ gzip: 0.10 kB
โน [ESM] 2 files, total: 0.19 kB
โ Build complete in 575ms
tsdown-dual-publish-esm-cjs v0.0.0
Build tools:
- typescript@~5.8.3
- tsdown@^0.14.2
No problems found ๐
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ "tsdown-dual-publish-esm-cjs" โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node10 โ ๐ข โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node16 (from CJS) โ ๐ข (CJS) โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ node16 (fromโฆ
This content originally appeared on DEV Community and was authored by Sean Boult
Sean Boult | Sciencx (2025-09-04T13:34:31+00:00) Dual publish ESM and CJS with tsdown. Retrieved from https://www.scien.cx/2025/09/04/dual-publish-esm-and-cjs-with-tsdown/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.