Static Files
Import
import { serveStatic } from "@hornjs/fest/static";
Basic Usage
import { serve } from "@hornjs/fest";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";
import { serveStatic } from "@hornjs/fest/static";
serve({
adapter: new NodeRuntimeAdapter(),
middleware: [serveStatic({ dir: "./public" })],
fetch: () => new Response("Not Found", { status: 404 }),
});
serveStatic() is ordinary middleware, so it can be placed anywhere in the
middleware chain.
ServeStaticOptions
dir
Base directory used for static file resolution.
methods
Allowed HTTP methods for static serving.
Defaults to:
GETHEAD
Requests using other methods fall through to downstream middleware or the final handler.
renderHTML
Optional hook for rewriting HTML content before sending the response.
serveStatic({
dir: "./public",
renderHTML: async ({ html, filename, request }) => {
return new Response(html.replace("</body>", `<p>${filename}</p></body>`), {
headers: { "content-type": "text/html; charset=utf-8" },
});
},
});
Resolution Rules
serveStatic() follows a few built-in path conventions:
/->index.html/about-> triesabout.html, thenabout/index.html- explicit extensions are used as-is
This makes it suitable for simple sites, SPA-style HTML fallbacks, and directory-based static content layouts.
Compression Behavior
If the request advertises compression support:
- Brotli is preferred when the runtime exposes Brotli compression
- gzip is used as a fallback
- otherwise the original file stream is returned
The response sets Content-Encoding and Vary: Accept-Encoding when
compression is applied.
Runtime Requirements
Static serving depends on runtime capabilities exposed through
request.runtime, including:
- path resolution
- opening files
- gzip and optional Brotli transforms
That means support depends on the active runtime adapter. For example, the stream runtime only exposes minimal capabilities, so static serving there is useful only if the host provides equivalent file access primitives.
Fallthrough Behavior
If no matching file is found, serveStatic() simply calls next(request).
That makes it easy to combine static assets with dynamic routes:
serve({
middleware: [serveStatic({ dir: "./public" })],
routes: {
"/api/pathname": (request) => Response.json({ pathname: new URL(request.url).pathname }),
},
fetch: () => new Response("Not Found", { status: 404 }),
});