Bytecode caching --bytecode flag basic usage
Enable bytecode caching with the --bytecode flag. When compiling TypeScript's tsc with bytecode enabled, startup time improves by 2x. Without --format specified, the output format defaults to CommonJS. The build command bun build ./index.ts --target=bun --bytecode --outdir=./dist writes two files: dist/index.js (bundled JavaScript in CommonJS) and dist/index.js.jsc (the bytecode cache file). At runtime, Bun automatically detects and uses the .jsc file.
Bytecode with standalone executables --compile
When creating an executable with --compile, Bun embeds the bytecode in the binary. Both ESM and CommonJS work. For ESM: bun build ./cli.ts --compile --bytecode --format=esm --outfile=mycli. For CommonJS: bun build ./cli.ts --compile --bytecode --outfile=mycli. The resulting executable contains both the code and the bytecode.
ESM bytecode requires --compile
ESM bytecode requires --compile because Bun embeds module metadata (import/export information) in the compiled binary. With this metadata, the JavaScript engine skips parsing entirely at runtime. Without --compile, ESM bytecode would still require parsing the source to analyze module dependencies, which defeats the purpose of bytecode caching.
Bytecode depth limiting with --bytecode-depth
Use --bytecode-depth (a non-negative integer) to compile only the top N levels of nesting. Functions past that limit are compiled from source when they are first called. --bytecode-depth=0 compiles only the top-level code of each module, no nested functions. --bytecode-depth=1 compiles top-level code and the functions it declares directly. A lower depth makes the .jsc file smaller. The same option is available as bytecodeDepth in Bun.build.
Combine bytecode with minification and sourcemaps
Combine bytecode with minification and source maps using: bun build --compile --bytecode --minify --sourcemap ./cli.ts --outfile=mycli. The --minify flag reduces code size before generating bytecode (less code -> less bytecode). The --sourcemap flag preserves error reporting (errors still point to original source). The --bytecode flag eliminates parsing overhead.
bun build --loader syntax
Bun's --loader syntax differs from esbuild. Use --loader .ext:loader instead of esbuild's --loader:.ext=loader. For example: bun build app.ts --loader .svg:text instead of esbuild app.ts --bundle --loader:.svg=text.
bun build --target replaces --platform
Bun uses --target instead of esbuild's --platform for consistency with tsconfig. Bun's --target does not support neutral.
bun build --sourcemap supported values
Bun's --sourcemap flag supports linked (the default when no value is given), external, inline, and none. It does not support esbuild's both.
bun build does not support --target for syntax downleveling
Bun's bundler performs no syntactic down-leveling. The esbuild --target flag is not supported.
bun build --asset-naming (renamed from --asset-names)
Bun uses --asset-naming instead of esbuild's --asset-names for consistency with naming in the JS API.
bun build --chunk-naming (renamed from --chunk-names)
Bun uses --chunk-naming instead of esbuild's --chunk-names for consistency with naming in the JS API.
bun build --entry-naming (renamed from --entry-names)
Bun uses --entry-naming instead of esbuild's --entry-names for consistency with naming in the JS API.
CLI flag syntax differences from esbuild
In Bun's CLI, boolean flags like --minify take no argument. Flags that take one value, like --outdir <path>, can be written as --outdir out or --outdir=out. Some flags, like --define, can be repeated: --define foo=bar --define bar=baz.
bun build --ignore-dce-annotations
Bun uses --ignore-dce-annotations instead of esbuild's --ignore-annotations.
bun build --jsx-runtime values
Bun's --jsx-runtime flag supports "automatic" (uses jsx transform) and "classic" (uses React.createElement), instead of esbuild's --jsx.
Bun jsx configuration reads from tsconfig.json by default
Bun reads compilerOptions.jsx from tsconfig.json to determine a default for JSX. If compilerOptions.jsx is "react-jsx" or if NODE_ENV=production, Bun uses the jsx transform. Otherwise, it uses jsxDEV. The bundler does not support preserve.
bun build --root (renamed from --outbase)
Bun uses --root instead of esbuild's --outbase.
bun build --tsconfig-override
Bun uses --tsconfig-override instead of esbuild's --tsconfig.
Bun bundler tree-shaking always enabled
Tree-shaking is always true in Bun. Bun also tree-shakes the exports of import() / require() targets down to the names the importing code reads (see splitting). esbuild keeps every export of a dynamically imported module.
bun build CLI example
The Bun CLI for building is: bun build <entrypoint> --outdir=out. Unlike esbuild, no --bundle flag is needed.
bun build --feature flag for compile-time dead-code elimination
Bun has a --feature flag that is Bun-specific. It enables feature flags for compile-time dead-code elimination through import { feature } from "bun:bundle".
bun build --no-bundle to disable bundling
Bun always bundles by default. Use the --no-bundle flag to disable bundling.
bun build --define syntax (no colon)
Bun's --define syntax does not use a colon, unlike esbuild. Use --define K=V instead of esbuild's --define:K=V.
bun build --external syntax (no colon)
Bun's --external syntax does not use a colon, unlike esbuild. Use --external <pkg> instead of esbuild's --external:<pkg>.
bun build --format supported values
Bun's --format flag supports "esm", "cjs", and "iife". esbuild defaults to "iife".