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 Modified
when 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 Found
if file doesn’t exist or becomes inaccessible - Last-Modified support - Uses file modification time for
If-Modified-Since
headers - If-Modified-Since - Returns
304 Not Modified
when file hasn’t changed since client’s cached version - Range request support - Automatically handles partial content requests with
Content-Range
headers - 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.