Skip to main content
To get started, import HTML files and pass them to the routes option in Bun.serve().
app.ts
terminal

HTML Routes

HTML Imports as Routes

The web starts with HTML, and so does Bun’s fullstack dev server. To specify entrypoints to your frontend, import HTML files into your JavaScript/TypeScript/TSX/JSX files.
app.ts
These HTML files are used as routes in Bun’s dev server you can pass to Bun.serve().
app.ts
When you make a request to /dashboard or /, Bun automatically bundles the <script> and <link> tags in the HTML files, exposes them as static routes, and serves the result.

HTML Processing Example

An index.html file like this:
index.html
Becomes something like this:
index.html

React Integration

To use React in your client-side code, import react-dom/client and render your app.

Development Mode

When building locally, enable development mode by setting development: true in Bun.serve().
src/backend.ts

Development Mode Features

When development is true, Bun will:
  • Include the SourceMap header in the response so that devtools can show the original source code
  • Disable minification
  • Re-bundle assets on each request to a .html file
  • Enable hot module reloading (unless hmr: false is set)
  • Echo console logs from browser to terminal

Advanced Development Configuration

Bun.serve() supports echoing console logs from the browser to the terminal. To enable this, pass console: true in the development object in Bun.serve().
src/backend.ts
When console: true is set, Bun will stream console logs from the browser to the terminal. This reuses the existing WebSocket connection from HMR to send the logs.

Development vs Production

Production Mode

Hot reloading and development: true helps you iterate quickly, but in production, your server should be as fast as possible and have as few external dependencies as possible. As of Bun v1.2.17, you can use Bun.build or bun build to bundle your full-stack application ahead of time.
terminal
When Bun’s bundler sees an HTML import from server-side code, it will bundle the referenced JavaScript/TypeScript/TSX/JSX and CSS files into a manifest object that Bun.serve() can use to serve the assets.
src/backend.ts

Runtime Bundling

When adding a build step is too complicated, you can set development: false in Bun.serve(). This will:
  • Enable in-memory caching of bundled assets. Bun will bundle assets lazily on the first request to an .html file, and cache the result in memory until the server restarts.
  • Enable Cache-Control headers and ETag headers
  • Minify JavaScript/TypeScript/TSX/JSX files
src/backend.ts

API Routes

HTTP Method Handlers

Define API endpoints with HTTP method handlers:
src/backend.ts

Dynamic Routes

Use URL parameters in your routes:
src/backend.ts

Request Handling

src/backend.ts

Plugins

Bun’s bundler plugins are also supported when bundling static routes. To configure plugins for Bun.serve, add a plugins array in the [serve.static] section of your bunfig.toml.

TailwindCSS Plugin

You can use TailwindCSS by installing and adding the tailwindcss package and bun-plugin-tailwind plugin.
terminal
bunfig.toml
This will allow you to use TailwindCSS utility classes in your HTML and CSS files. Import tailwindcss somewhere in your project:
index.html
Alternatively, you can import TailwindCSS in your CSS file:
style.css
index.html

Custom Plugins

Any JS file or module which exports a valid bundler plugin object (essentially an object with a name and setup field) can be placed inside the plugins array:
bunfig.toml
my-plugin-implementation.ts
Bun will lazily resolve and load each plugin and use them to bundle your routes.
This is currently in bunfig.toml to make it possible to know statically which plugins are in use when we eventually integrate this with the bun build CLI. These plugins work in Bun.build()’s JS API, but are not yet supported in the CLI.

Inline Environment Variables

Bun can replace process.env.* references in your frontend JavaScript and TypeScript with their actual values at build time. Configure the env option in your bunfig.toml:
bunfig.toml
This only works with literal process.env.FOO references, not import.meta.env or indirect access like const env = process.env; env.FOO.If an environment variable is not set, you may see runtime errors like ReferenceError: process is not defined in the browser.
See the HTML & static sites documentation for more details on build-time configuration and examples.

How It Works

Bun uses HTMLRewriter to scan for <script> and <link> tags in HTML files, uses them as entrypoints for Bun’s bundler, generates an optimized bundle for the JavaScript/TypeScript/TSX/JSX and CSS files, and serves the result.

Processing Pipeline

1

1. <script> Processing

  • Transpiles TypeScript, JSX, and TSX in <script> tags
  • Bundles imported dependencies
  • Generates sourcemaps for debugging
  • Minifies when development is not true in Bun.serve()
index.html
2

2. <link> Processing

  • Processes CSS imports and <link> tags
  • Concatenates CSS files
  • Rewrites url and asset paths to include content-addressable hashes in URLs
index.html
3

3. <img> & Asset Processing

  • Links to assets are rewritten to include content-addressable hashes in URLs
  • Small assets in CSS files are inlined into data: URLs, reducing the total number of HTTP requests sent over the wire
4

4. HTML Rewriting

  • Combines all <script> tags into a single <script> tag with a content-addressable hash in the URL
  • Combines all <link> tags into a single <link> tag with a content-addressable hash in the URL
  • Outputs a new HTML file
5

5. Serving

  • All the output files from the bundler are exposed as static routes, using the same mechanism internally as when you pass a Response object to static in Bun.serve().
  • This works similarly to how Bun.build processes HTML files.

Complete Example

Here’s a complete fullstack application example:
server.ts
public/index.html
src/main.tsx
src/App.tsx
src/styles.css

Best Practices

Project Structure

Environment-Based Configuration

server/config.ts

Error Handling

server/middleware.ts

API Response Helpers

server/utils.ts

Type Safety

types/api.ts

Deployment

Production Build

terminal

Docker Deployment

Dockerfile

Environment Variables

.env.production

Migration from Other Frameworks

From Express + Webpack

server.ts

From Next.js API Routes

server.ts

Limitations and Future Plans

Current Limitations

  • bun build CLI integration is not yet available for fullstack apps
  • Auto-discovery of API routes is not implemented
  • Server-side rendering (SSR) is not built-in

Planned Features

  • Integration with bun build CLI
  • File-based routing for API endpoints
  • Built-in SSR support
  • Enhanced plugin ecosystem
This is a work in progress. Features and APIs may change as Bun continues to evolve.