From 5bdcf339d71a5541587603f25067765af5d39a41 Mon Sep 17 00:00:00 2001 From: robobun Date: Thu, 31 Jul 2025 22:06:35 -0700 Subject: [PATCH] Document static routes vs file routes in HTTP server (#21506) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add comprehensive documentation distinguishing static routes from file routes in `Bun.serve()` - Document caching behavior differences: ETag vs Last-Modified - Explain performance characteristics and error handling differences - Provide clear use case recommendations ## Changes - **File Responses vs Static Responses** section explaining the two approaches - **HTTP Caching Behavior** section detailing ETag and Last-Modified support - **Status Code Handling** section covering automatic 204/304 responses - Code examples showing both patterns with clear explanations ## Key Documentation Points - Static routes (`new Response(await file.bytes())`) buffer content in memory at startup - File routes (`new Response(Bun.file(path))`) read from filesystem per request - Static routes use ETags for caching, file routes use Last-Modified headers - File routes handle 404s automatically, static routes cause startup errors for missing files - Both support HTTP caching standards but with different validation strategies 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Bot Co-authored-by: Claude Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- docs/api/http.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/docs/api/http.md b/docs/api/http.md index e5b052fed9..f3e5b48e55 100644 --- a/docs/api/http.md +++ b/docs/api/http.md @@ -164,6 +164,70 @@ Static responses do not allocate additional memory after initialization. You can 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: + +```ts +Bun.serve({ + routes: { + // Static route - content is buffered in memory at startup + "/logo.png": new Response(await Bun.file("./logo.png").bytes()), + + // File route - content is read from filesystem on each request + "/download.zip": new Response(Bun.file("./download.zip")), + }, +}); +``` + +**Static routes** (`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 + +**File routes** (`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 + +### HTTP Caching Behavior + +Both route types implement HTTP caching standards but with different strategies: + +#### Static Routes Caching + +- **ETag generation**: Automatically computes ETag hash from content at startup +- **If-None-Match**: Validates client ETag against server ETag +- **304 responses**: Returns `304 Not Modified` with empty body when ETags match +- **Cache headers**: Inherits any `Cache-Control` headers you provide in the Response +- **Consistency**: ETag remains constant until server restart or route reload + +#### File Routes Caching + +- **Last-Modified**: Uses file's `mtime` for `Last-Modified` header +- **If-Modified-Since**: Compares client date with file modification time +- **304 responses**: Returns `304 Not Modified` when file unchanged since client's cached version +- **Content-Length**: Automatically set based on current file size +- **Dynamic validation**: Checks file modification time on each request + +#### Status Code Handling + +Both route types automatically adjust status codes: + +- **200 → 204**: Empty files (0 bytes) return `204 No Content` instead of `200 OK` +- **200 → 304**: Successful cache validation returns `304 Not Modified` +- **File routes only**: Missing or inaccessible files return `404 Not Found` + ```ts const server = Bun.serve({ static: {