Bundling programmatically with Bun.build()
Published December 4, 2026
try {
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
});
for (const artifact of result.outputs) console.log(artifact.kind, artifact.path);
} catch (err) {
const error = err as AggregateError;
console.error(`Build failed with ${error.errors.length} error(s)`, error);
}
export {};What
Bun.build({ entrypoints, outdir, ... }) runs Bun's native bundler from JavaScript and resolves
to { success, outputs, logs } — the same bundler behind the bun build CLI, callable
programmatically as part of a larger script.
Why it matters
Shelling out to bun build from a script means parsing CLI flags out of an object, capturing
stdout, and re-parsing text to know what happened. Bun.build() skips all of that: options are
a typed object, and the result is structured data — an array of BuildArtifact objects (each
one a Blob with .path, .kind, and .loader) plus a logs array of warnings. That makes it
straightforward to build tooling around bundling — a custom CLI, a deploy script that inspects
what got produced, or a dev server that bundles on demand and streams an artifact straight into
a Response.
How it works
entrypointsandoutdirmirror the CLI's positional entry file and--outdir;minify: trueis the JS-API equivalent of--minify.- On a genuine build failure (a syntax error, an unresolved import),
Bun.build()rejects the promise with anAggregateErrorrather than resolving withsuccess: false— that's why the real error handling here is thecatchblock, not anifcheck on the resolved value.error.errorsis an array ofBuildMessage/ResolveMessageinstances with a.messageand.positiondescribing exactly where each failure is. - On success,
result.outputsholds every generated file — entrypoints, chunks, sourcemaps — each already aBlob-like object, soartifact.text()ornew Response(artifact)works without a separateBun.file()read. result.logs(not shown failing here) still gets populated with non-fatal warnings even on a successful build — worth checking in CI even when the build otherwise "passes."
Gotchas
- Don't reach for
result.successas the primary failure signal the way you might expect from the CLI's exit code — an uncaught rejection here crashes the script if it isn't wrapped intry/catch(or a.catch()). outdirwrites files with content-hashed or path-based names depending onnaming— the bundled entrypoint usually isn't literallyoutdir/index.jsunless the entrypoint file is named that.- Bundling every time a script runs has a real cost; for a dev server this is fine (
Bun.build()is fast), but a CI pipeline that rebuilds unnecessarily on every step still pays that cost each time.
Related
bun build --compileproduces a standalone executable; the same behavior is available asBun.build({ compile: { outfile } })for scripting a cross-compiled release.- The Bun.$ shell scripting post covers wrapping a build step in cleanup/versioning logic
alongside
Bun.build().