As of Bun v1.1.44, we've added initial support for bundling frontend apps directly in Bun's HTTP server: `Bun.serve()`. Run your frontend and backend in the same app with no extra steps. To get started, import your HTML files and pass them to the `static` option in `Bun.serve()`. ```ts import dashboard from "./dashboard.html"; import homepage from "./index.html"; Bun.serve({ // Add HTML imports to `static` static: { // Bundle & route index.html to "/" "/": homepage, // Bundle & route dashboard.html to "/dashboard" "/dashboard": dashboard, }, // Enable development mode for: // - Detailed error messages // - Rebuild on request development: true, // Handle API requests async fetch(req) { // ...your API code if (req.url.endsWith("/api/users")) { const users = await Bun.sql`SELECT * FROM users`; return Response.json(users); } // Return 404 for unmatched routes return new Response("Not Found", { status: 404 }); }, }); ``` You'll need to run your app with `bun --experimental-html` to enable this feature: ```bash $ bun --experimental-html run app.ts ``` ## HTML imports are 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. ```ts import dashboard from "./dashboard.html"; import homepage from "./index.html"; ``` These HTML files are used as routes in Bun's dev server you can pass to `Bun.serve()`. ```ts Bun.serve({ static: { "/": homepage, "/dashboard": dashboard, } fetch(req) { // ... api requests }, }); ``` When you make a request to `/dashboard` or `/`, Bun automatically bundles the ` ``` Becomes something like this: ```html#index.html Home
``` ### How to use with React To use React in your client-side code, import `react-dom/client` and render your app. {% codetabs %} ```ts#src/backend.ts import dashboard from "./public/dashboard.html"; import { serve } from "bun"; serve({ static: { "/": dashboard, }, async fetch(req) { // ...api requests return new Response("hello world"); }, }); ``` ```ts#src/frontend.tsx import "./styles.css"; import { createRoot } from "react-dom/client"; import { App } from "./app.tsx"; document.addEventListener("DOMContentLoaded", () => { const root = createRoot(document.getElementById("root")); root.render(); }); ``` ```html#public/dashboard.html Dashboard
``` ```css#src/styles.css body { background-color: red; } ``` ```tsx#src/app.tsx export function App() { return
Hello World
; } ``` {% /codetabs %} ### Development mode When building locally, enable development mode by setting `development: true` in `Bun.serve()`. ```js-diff import homepage from "./index.html"; import dashboard from "./dashboard.html"; Bun.serve({ static: { "/": homepage, "/dashboard": dashboard, } + development: true, fetch(req) { // ... api requests }, }); ``` 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 #### Production mode When serving your app in production, set `development: false` in `Bun.serve()`. - 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. - Enables `Cache-Control` headers and `ETag` headers - Minifies JavaScript/TypeScript/TSX/JSX files ## How this works Bun uses [`HTMLRewriter`](/docs/api/html-rewriter) to scan for ` ``` 2. **`` processing** - Processes CSS imports and `` tags - Concatenates CSS files - Rewrites `url` and asset paths to include content-addressable hashes in URLs ```html ``` 3. **`` & 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. **Rewrite HTML** - Combines all `