Skip to main content
Bun’s fast native bundler is available via the bun build CLI command or the Bun.build() JavaScript API.

At a glance

  • JS API: await Bun.build({ entrypoints, outdir })
  • CLI: bun build <entrypoint> --outdir ./out
  • Watch mode: --watch for incremental rebuilds
  • Targets: --target browser|bun|node
  • Formats: --format esm|cjs|iife (cjs/iife experimental)
build.ts
await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});
It’s fast. The numbers below are based on esbuild’s three.js benchmark.
Bundling 10 copies of three.js from scratch, with sourcemaps and minification

Why bundle?

Bundlers are a critical piece of infrastructure in the JavaScript ecosystem. Here’s a quick overview of why bundling is important:
  • Reduce HTTP requests. A single package in node_modules may consist of hundreds of files, and large applications may have dozens of such dependencies. Loading each of these files with a separate HTTP request becomes untenable very quickly, so bundlers are used to convert our source code into a smaller number of self-contained “bundles” that can be loaded with a single request.
  • Code transforms. Modern apps are commonly built with languages and tools like TypeScript, JSX, and CSS modules that don’t run natively in browsers. Bundlers are the natural place to configure this build-time code transformation.
  • Framework features. Frameworks rely on bundler plugins and code transforms to implement common patterns like file-system routing, client-server code co-location (e.g. getServerSideProps or Remix loaders), and server components.
  • Full-stack apps. Bun’s bundler can handle both server-side and client-side code in a single command, with support for optimized production builds and standalone executables. With build-time HTML imports, you can bundle your entire application (frontend assets and backend server) as a single deployable unit.
Let’s jump into the bundler’s API.
The Bun bundler is not a replacement for tsc for typechecking or generating type declarations.

Basic example

Let’s build our first bundle. You have the following two files, which implement a simple client-side-rendered React app.
import * as ReactDOM from "react-dom/client";
import { Component } from "./Component";

const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(<Component message="Sup!" />);
Here, index.tsx is the “entrypoint” to our application. Commonly, this is a file that performs some side effects like starting a server or—in this case—initializing a React root. Because it uses TypeScript and JSX, we need to bundle our code before it can be sent to the browser. To create our bundle:
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
});
For each file in the entrypoints array, Bun will generate a new bundle. This bundle will be written to disk in the ./out directory (resolved relative to the current working directory). After running the build, the file system looks like this:
.
├── index.tsx
├── Component.tsx
└── out
    └── index.js
The contents of out/index.js will look something like this:
// out/index.js
// ...
// ~20k lines of code
// including the contents of `react-dom/client` and all its dependencies
// this defines $jsxDEV and $createRoot

// Component.tsx
function Component(props) {
  return $jsxDEV(
    "p",
    {
      children: props.message,
    },
    undefined,
    false,
    undefined,
    this,
  );
}

// index.tsx
var rootNode = document.getElementById("root");
var root = $createRoot(rootNode);
root.render(
  $jsxDEV(
    Component,
    {
      message: "Sup!",
    },
    undefined,
    false,
    undefined,
    this,
  ),
);

Watch mode

Like the runtime and test runner, the bundler supports watch mode natively.
bun build ./index.tsx --outdir ./out --watch

Content types

Like the Bun runtime, the bundler supports an array of file types out of the box. The following table breaks down the bundler’s set of default “loaders”. Refer to Bundler > Loaders for full documentation.
ExtensionLoaderDescription
.js .cjs .mjs .mts .cts .ts .tsx .jsxJavaScript/TypeScriptParse and transpile TypeScript/JSX syntax to vanilla JavaScript. Default transformations include dead code elimination and tree shaking. Currently Bun does not attempt to down-convert syntax; the use of recent JavaScript syntax in your code will be reflected in the bundled code.
.jsonJSONParse JSON files and inline them into the bundle as JavaScript objects.
.tomlTOMLParse TOML files and inline them as JavaScript objects.
.yaml .ymlYAMLParse YAML files and inline them as JavaScript objects.
.txtTextRead text files as strings and inline them into the bundle.
.htmlHTMLProcess HTML files, bundling referenced assets (scripts, stylesheets, images, etc.).
.cssCSSBundle all imported CSS files into a single .css file that is written to the output directory.
.node .wasmNativeThese files are supported by the Bun runtime, but during bundling they are treated as assets.

Assets

If the bundler encounters an import with an unrecognized extension, it treats the imported file as an external file. The referenced file is copied as-is into outdir, and the import is replaced with a variable containing the path to the file.
// bundle entrypoint
import logo from "./logo.svg";
console.log(logo);
The behavior of the file loader is also impacted by naming and publicPath.
Refer to the Bundler > Loaders page for complete documentation.

Plugins

The behavior described in the table above can be overridden or extended with plugins. Refer to the Bundler > Loaders page for complete documentation.

Key features

Code splitting

When multiple entry points share code, the bundler can extract shared dependencies into separate chunks. This is called code splitting.
bun build ./entry-a.tsx ./entry-b.tsx --outdir ./out --splitting
See Bundler > API for details.

Tree shaking

The bundler performs dead code elimination and tree shaking to remove unused code from your bundle. This happens automatically—no configuration required.

Minification

The bundler supports multiple levels of minification:
bun build ./index.tsx --outdir ./out --minify
bun build ./index.tsx --outdir ./out --minify-whitespace
bun build ./index.tsx --outdir ./out --minify-identifiers
bun build ./index.tsx --outdir ./out --minify-syntax

Source maps

Generate source maps for easier debugging:
bun build ./index.tsx --outdir ./out --sourcemap=external
bun build ./index.tsx --outdir ./out --sourcemap=inline
bun build ./index.tsx --outdir ./out --sourcemap=linked

Environment variables

Inline environment variables at build time:
bun build ./index.tsx --outdir ./out --env inline
bun build ./index.tsx --outdir ./out --env PUBLIC_*

Next steps

Loaders

Learn about file loaders and content types

Plugins

Extend the bundler with plugins

Macros

Run code at build time with macros

Executables

Compile standalone executables

CSS

Bundle and transform CSS

HTML

Process HTML with bundled assets

Build docs developers (and LLMs) love