Bun.serve() by using the routes property (for static paths, parameters, and wildcards) or by handling unmatched requests with the fetch method.
Bun.serve()’s router builds on top uWebSocket’s tree-based approach to add SIMD-accelerated route parameter decoding and JavaScriptCore structure caching to push the performance limits of what modern hardware allows.
Basic Setup
Bun.serve() receive a BunRequest (which extends Request) and return a Response or Promise<Response>. This makes it easier to use the same code for both sending & receiving HTTP requests.
Asynchronous Routes
Async/await
You can use async/await in route handlers to return aPromise<Response>.
Promise
You can also return aPromise<Response> from a route handler.
Route precedence
Routes are matched in order of specificity:- Exact routes (
/users/all) - Parameter routes (
/users/:id) - Wildcard routes (
/users/*) - Global catch-all (
/*)
Type-safe route parameters
TypeScript parses route parameters when passed as a string literal, so that your editor will show autocomplete when accessingrequest.params.
index.ts
&0xFFFD;.
Static responses
Routes can also beResponse objects (without the handler function). Bun.serve() optimizes it for zero-allocation dispatch - perfect for health checks, redirects, and fixed content:
Response object.
Static route responses are cached for the lifetime of the server object. To reload static routes, call server.reload(options).
File Responses vs Static Responses
When serving files in routes, there are two distinct behaviors depending on whether you buffer the file content or serve it directly:new Response(await file.bytes())) buffer content in memory at startup:
- Zero filesystem I/O during requests - content served entirely from memory
- ETag support - Automatically generates and validates ETags for caching
- If-None-Match - Returns
304 Not Modifiedwhen client ETag matches - No 404 handling - Missing files cause startup errors, not runtime 404s
- Memory usage - Full file content stored in RAM
- Best for: Small static assets, API responses, frequently accessed files
new Response(Bun.file(path))) read from filesystem per request:
- Filesystem reads on each request - checks file existence and reads content
- Built-in 404 handling - Returns
404 Not Foundif file doesn’t exist or becomes inaccessible - Last-Modified support - Uses file modification time for
If-Modified-Sinceheaders - If-Modified-Since - Returns
304 Not Modifiedwhen file hasn’t changed since client’s cached version - Range request support - Automatically handles partial content requests with
Content-Rangeheaders - Streaming transfers - Uses buffered reader with backpressure handling for efficient memory usage
- Memory efficient - Only buffers small chunks during transfer, not entire file
- Best for: Large files, dynamic content, user uploads, files that change frequently
Streaming files
To stream a file, return aResponse object with a BunFile object as the body.
⚡️ Speed — Bun automatically uses the
sendfile(2) system call when possible,
enabling zero-copy file transfers in the kernel—the fastest way to send files.slice(start, end) method on the Bun.file object. This automatically sets the Content-Range and Content-Length headers on the Response object.
fetch request handler
The fetch handler handles incoming requests that weren’t matched by any route. It receives a Request object and returns a Response or Promise<Response>.
fetch handler supports async/await:
Server object from the fetch handler. It’s the second argument passed to the fetch function.