Bun's bundler API is inspired heavily by esbuild. Migrating to Bun's bundler from esbuild should be relatively painless. This guide will briefly explain why you might consider migrating to Bun's bundler and provide a side-by-side API comparison reference for those who are already familiar with esbuild's API.
There are a few behavioral differences to note.
- Bundling by default. Unlike esbuild, Bun always bundles by default. This is why the
--bundle
flag isn't necessary in the Bun example. To transpile each file individually, useBun.Transpiler
. - It's just a bundler. Unlike esbuild, Bun's bundler does not include a built-in development server or file watcher. It's just a bundler. The bundler is intended for use in conjunction with
Bun.serve
and other runtime APIs to achieve the same effect. As such, all options relating to HTTP/file watching are not applicable.
Performance
With a performance-minded API coupled with the extensively optimized Zig-based JS/TS parser, Bun's bundler is 1.75x faster than esbuild on esbuild's three.js benchmark.
CLI API
Bun and esbuild both provide a command-line interface.
esbuild <entrypoint> --outdir=out --bundle
bun build <entrypoint> --outdir=out
In Bun's CLI, simple boolean flags like --minify
do not accept an argument. Other flags like --outdir <path>
do accept an argument; these flags can be written as --outdir out
or --outdir=out
. Some flags like --define
can be specified several times: --define foo=bar --define bar=baz
.
esbuild | bun build | |
---|---|---|
--bundle | n/a | Bun always bundles, use --no-bundle to disable this behavior. |
|
| Small syntax difference; no colon.
|
|
| Small syntax difference; no colon.
|
--format | --format | Bun supports "esm" and "cjs" currently, but more module formats are planned. esbuild defaults to "iife" . |
|
| Bun supports a different set of built-in loaders than esbuild; see Bundler > Loaders for a complete reference. The esbuild loaders The syntax for
|
--minify | --minify | No differences |
--outdir | --outdir | No differences |
--outfile | --outfile | |
--packages | --packages | No differences |
--platform | --target | Renamed to --target for consistency with tsconfig. Does not support neutral . |
--serve | n/a | Not applicable |
--sourcemap | --sourcemap | No differences |
--splitting | --splitting | No differences |
--target | n/a | No supported. Bun's bundler performs no syntactic down-leveling at this time. |
--watch | --watch | No differences |
--allow-overwrite | n/a | Overwriting is never allowed |
--analyze | n/a | Not supported |
--asset-names | --asset-naming | Renamed for consistency with naming in JS API |
--banner | --banner | Only applies to js bundles |
--footer | --footer | Only applies to js bundles |
--certfile | n/a | Not applicable |
--charset=utf8 | n/a | Not supported |
--chunk-names | --chunk-naming | Renamed for consistency with naming in JS API |
--color | n/a | Always enabled |
--drop | --drop | |
--entry-names | --entry-naming | Renamed for consistency with naming in JS API |
--global-name | n/a | Not applicable, Bun does not support iife output at this time |
--ignore-annotations | --ignore-dce-annotations | |
--inject | n/a | Not supported |
--jsx | --jsx-runtime <runtime> | Supports "automatic" (uses jsx transform) and "classic" (uses React.createElement ) |
--jsx-dev | n/a | Bun reads compilerOptions.jsx from tsconfig.json to determine a default. If compilerOptions.jsx is "react-jsx" , or if NODE_ENV=production , Bun will use the jsx transform. Otherwise, it uses jsxDEV . For any to Bun uses jsxDEV . The bundler does not support preserve . |
--jsx-factory | --jsx-factory | |
--jsx-fragment | --jsx-fragment | |
--jsx-import-source | --jsx-import-source | |
--jsx-side-effects | n/a | JSX is always assumed to be side-effect-free |
--keep-names | n/a | Not supported |
--keyfile | n/a | Not applicable |
--legal-comments | n/a | Not supported |
--log-level | n/a | Not supported. This can be set in bunfig.toml as logLevel . |
--log-limit | n/a | Not supported |
--log-override:X=Y | n/a | Not supported |
--main-fields | n/a | Not supported |
--mangle-cache | n/a | Not supported |
--mangle-props | n/a | Not supported |
--mangle-quoted | n/a | Not supported |
--metafile | n/a | Not supported |
--minify-whitespace | --minify-whitespace | |
--minify-identifiers | --minify-identifiers | |
--minify-syntax | --minify-syntax | |
--out-extension | n/a | Not supported |
--outbase | --root | |
--preserve-symlinks | n/a | Not supported |
--public-path | --public-path | |
--pure | n/a | Not supported |
--reserve-props | n/a | Not supported |
--resolve-extensions | n/a | Not supported |
--servedir | n/a | Not applicable |
--source-root | n/a | Not supported |
--sourcefile | n/a | Not supported. Bun does not support stdin input yet. |
--sourcemap | --sourcemap | No differences |
--sources-content | n/a | Not supported |
--supported | n/a | Not supported |
--tree-shaking | n/a | Always true |
--tsconfig | --tsconfig-override | |
--version | n/a | Run bun --version to see the version of Bun. |
JavaScript API
esbuild.build() | Bun.build() | |
---|---|---|
absWorkingDir | n/a | Always set to process.cwd() |
alias | n/a | Not supported |
allowOverwrite | n/a | Always false |
|
| Uses same templating syntax as esbuild, but
|
banner | n/a | Not supported |
bundle | n/a | Always true . Use Bun.Transpiler to transpile without bundling. |
charset | n/a | Not supported |
|
| Uses same templating syntax as esbuild, but
|
color | n/a | Bun returns logs in the logs property of the build result. |
conditions | n/a | Not supported. Export conditions priority is determined by target . |
define | define | |
drop | n/a | Not supported |
|
| Bun supports a
|
entryPoints | entrypoints | Capitalization difference |
external | external | No differences |
footer | n/a | Not supported |
format | format | Only supports "esm" currently. Support for "cjs" and "iife" is planned. |
globalName | n/a | Not supported |
ignoreAnnotations | n/a | Not supported |
inject | n/a | Not supported |
jsx | jsx | Not supported in JS API, configure in tsconfig.json |
jsxDev | jsxDev | Not supported in JS API, configure in tsconfig.json |
jsxFactory | jsxFactory | Not supported in JS API, configure in tsconfig.json |
jsxFragment | jsxFragment | Not supported in JS API, configure in tsconfig.json |
jsxImportSource | jsxImportSource | Not supported in JS API, configure in tsconfig.json |
jsxSideEffects | jsxSideEffects | Not supported in JS API, configure in tsconfig.json |
keepNames | n/a | Not supported |
legalComments | n/a | Not supported |
loader | loader | Bun supports a different set of built-in loaders than esbuild; see Bundler > Loaders for a complete reference. The esbuild loaders dataurl , binary , base64 , copy , and empty are not yet implemented. |
logLevel | n/a | Not supported |
logLimit | n/a | Not supported |
logOverride | n/a | Not supported |
mainFields | n/a | Not supported |
mangleCache | n/a | Not supported |
mangleProps | n/a | Not supported |
mangleQuoted | n/a | Not supported |
metafile | n/a | Not supported |
|
| In Bun,
|
minifyIdentifiers | minify.identifiers | See minify |
minifySyntax | minify.syntax | See minify |
minifyWhitespace | minify.whitespace | See minify |
nodePaths | n/a | Not supported |
outExtension | n/a | Not supported |
outbase | root | Different name |
outdir | outdir | No differences |
outfile | outfile | No differences |
packages | n/a | Not supported, use external |
platform | target | Supports "bun" , "node" and "browser" (the default). Does not support "neutral" . |
plugins | plugins | Bun's plugin API is a subset of esbuild's. Some esbuild plugins will work out of the box with Bun. |
preserveSymlinks | n/a | Not supported |
publicPath | publicPath | No differences |
pure | n/a | Not supported |
reserveProps | n/a | Not supported |
resolveExtensions | n/a | Not supported |
sourceRoot | n/a | Not supported |
sourcemap | sourcemap | Supports "inline" , "external" , and "none" |
sourcesContent | n/a | Not supported |
splitting | splitting | No differences |
stdin | n/a | Not supported |
supported | n/a | Not supported |
target | n/a | No support for syntax downleveling |
treeShaking | n/a | Always true |
tsconfig | n/a | Not supported |
write | n/a | Set to true if outdir /outfile is set, otherwise false |
Plugin API
Bun's plugin API is designed to be esbuild compatible. Bun doesn't support esbuild's entire plugin API surface, but the core functionality is implemented. Many third-party esbuild
plugins will work out of the box with Bun.
Long term, we aim for feature parity with esbuild's API, so if something doesn't work please file an issue to help us prioritize.
Plugins in Bun and esbuild are defined with a builder
object.
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(builder) {
// define plugin
},
};
The builder
object provides some methods for hooking into parts of the bundling process. Bun implements onResolve
and onLoad
; it does not yet implement the esbuild hooks onStart
, onEnd
, and onDispose
, and resolve
utilities. initialOptions
is partially implemented, being read-only and only having a subset of esbuild's options; use config
(same thing but with Bun's BuildConfig
format) instead.
import type { BunPlugin } from "bun";
const myPlugin: BunPlugin = {
name: "my-plugin",
setup(builder) {
builder.onResolve(
{
/* onResolve.options */
},
args => {
return {
/* onResolve.results */
};
},
);
builder.onLoad(
{
/* onLoad.options */
},
args => {
return {
/* onLoad.results */
};
},
);
},
};
onResolve
options
🟢 | filter |
---|---|
🟢 | namespace |
arguments
🟢 | path |
---|---|
🟢 | importer |
🔴 | namespace |
🔴 | resolveDir |
🔴 | kind |
🔴 | pluginData |
results
🟢 | namespace |
---|---|
🟢 | path |
🔴 | errors |
🔴 | external |
🔴 | pluginData |
🔴 | pluginName |
🔴 | sideEffects |
🔴 | suffix |
🔴 | warnings |
🔴 | watchDirs |
🔴 | watchFiles |
onLoad
options
🟢 | filter |
🟢 | namespace |
arguments
🟢 | path |
🔴 | namespace |
🔴 | suffix |
🔴 | pluginData |
results
🟢 | contents |
🟢 | loader |
🔴 | errors |
🔴 | pluginData |
🔴 | pluginName |
🔴 | resolveDir |
🔴 | warnings |
🔴 | watchDirs |
🔴 | watchFiles |