docs/latest/concepts/architecture.md
Fresh is a server-first web framework. Pages are rendered on the server and only the interactive parts (islands) ship JavaScript to the browser. This page explains how a request flows through the framework.
Every page is fully rendered to HTML on the server before being sent to the browser. This means:
Fresh uses the
islands architecture. Only
components in the islands/ directory are hydrated in
the browser. Everything else is static HTML that never runs JavaScript on the
client.
This means a page with a single interactive button only ships the JavaScript for that button - not for the entire page.
Middlewares execute in registration order, wrapping the handler. Each middleware
calls ctx.next() to pass control to the next middleware (or handler). This
creates an onion-like pattern where middlewares can act on both the request
(before ctx.next()) and the response (after ctx.next()):
app.use(async (ctx) => {
// Before: runs on the way in
console.log("Request:", ctx.url.pathname);
const response = await ctx.next();
// After: runs on the way out
console.log("Status:", response.status);
return response;
});
Scoped middleware runs only for requests that match a specific path prefix. Pass
a path pattern as the first argument to app.use():
app.use("/admin/*", async (ctx) => {
// Only runs for /admin/* routes
const user = ctx.state.user;
if (!user?.isAdmin) return new Response("Forbidden", { status: 403 });
return ctx.next();
});
Global middleware runs on every request; scoped middleware lets you apply logic like authentication or logging to a subset of routes.
Layouts wrap page components and are inherited from
parent directories. A page at routes/blog/post.tsx inherits layouts from:
routes/_layout.tsx (root layout)routes/blog/_layout.tsx (section layout)Layouts nest from the outside in: the root layout is outermost, each deeper
layout wraps closer to the page, and the innermost layout directly wraps the
page component. The app wrapper (_app.tsx) wraps
everything.
Fresh uses Vite to bundle island JavaScript for production.
The deno task build command:
_fresh/server.js)In production, _fresh/server.js serves the pre-built assets. In development,
Vite provides Hot Module Replacement for instant feedback.