Bundle and Tree-Shake a Library for Both ESM and CJS Consumers
Bun's bundler exposed via bun build can emit ESM, CJS, and IIFE targets from a single source tree, and it performs dead-code elimination using a scope-aware AST analysis rather than naive string matching. The --packages=external flag keeps dependencies out of the bundle so they resolve at install time, which is the correct choice for libraries, while --minify and --sourcemap=external control output shape. Internally Bun parses each module once, builds a dependency graph, and emits per-format outputs with correct import and require interop shims.
Publishing dual-format libraries is a persistent pain point in the npm ecosystem, and this workflow is production-grade for SDK authors, internal component libraries, and monorepo shared packages. Teams wire it into a prepublishOnly script so every npm publish produces consistent dist artifacts, and they commit a package.json exports map pointing to the correct file per condition. This eliminates the classic dual-package hazard where a consumer loads both ESM and CJS copies of the same module.
Security considerations: bundling third-party code into your dist means you inherit its vulnerabilities and any license obligations, so keep dependencies external for libraries unless a specific vendoring reason exists. Sourcemaps should be external and shipped separately, or omitted, to avoid exposing internal source paths in published packages. A frequent pitfall is forgetting to mark Node built-ins as external, which causes Bun to attempt to bundle fs, path, and similar modules and fail. Also verify that the exports field in package.json is correct, because a misordered conditions map silently breaks ESM consumers on modern bundlers.
> System.Execute()
# Build ESM and CJS outputs for a library
bun build ./src/index.ts \
--outdir ./dist \
--target=node \
--format=esm \
--packages=external \
--sourcemap=external \
--minify \
--naming='[dir]/[name].mjs'
bun build ./src/index.ts \
--outdir ./dist \
--target=node \
--format=cjs \
--packages=external \
--sourcemap=external \
--minify \
--naming='[dir]/[name].cjs'
# package.json excerpt
# "exports": { "import": "./dist/index.mjs", "require": "./dist/index.cjs" }
> Architecture & Security Context
Verified for Valters IT Hub. When deploying this configuration in a production homelab or enterprise environment, ensure that you monitor system resources and implement strict access controls. Administrator privileges are required.
ID: VALTERSIT-57259A3B9D20