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
Bun.serve().
app.ts
/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
Anindex.html file like this:
index.html
index.html
React Integration
To use React in your client-side code, importreact-dom/client and render your app.
Development Mode
When building locally, enable development mode by settingdevelopment: true in Bun.serve().
src/backend.ts
Development Mode Features
Whendevelopment 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
.htmlfile - Enable hot module reloading (unless
hmr: falseis 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
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 anddevelopment: true helps you iterate quickly, but in production, your server should be as fast as possible and have as few external dependencies as possible.
Ahead of Time Bundling (Recommended)
As of Bun v1.2.17, you can useBun.build or bun build to bundle your full-stack application ahead of time.
terminal
Bun.serve() can use to serve the assets.
src/backend.ts
Runtime Bundling
When adding a build step is too complicated, you can setdevelopment: false in Bun.serve().
This will:
- Enable in-memory caching of bundled assets. Bun will bundle assets lazily on the first request to an
.htmlfile, and cache the result in memory until the server restarts. - Enable
Cache-Controlheaders andETagheaders - 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 forBun.serve, add a plugins array in the [serve.static] section of your bunfig.toml.
TailwindCSS Plugin
You can use TailwindCSS by installing and adding thetailwindcss package and bun-plugin-tailwind plugin.
terminal
bunfig.toml
tailwindcss somewhere in your project:
index.html
style.css
index.html
Custom Plugins
Any JS file or module which exports a valid bundler plugin object (essentially an object with aname and setup field) can be placed inside the plugins array:
bunfig.toml
my-plugin-implementation.ts
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 replaceprocess.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.How It Works
Bun usesHTMLRewriter 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
developmentis nottrueinBun.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
staticinBun.serve(). - This works similarly to how
Bun.buildprocesses 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 buildCLI 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 buildCLI - 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.