Pick a topic from the menu.
Introducing Fresh 3:
Preact and Vite, with file-system routing and signals. Server-render by default, and ship JavaScript only for the islands that need it.
npm create @frsh/app@latest
pnpm create @frsh/app
yarn create @frsh/app
deno run -A npm:@frsh/create-app
Every route renders on the server as a Preact component. Zero JavaScript hits the browser unless you opt in with an island. Pages are fast because they start as plain HTML.
export default function HomePage() {
const now = Temporal.Now.plainDateTimeISO()
.toLocaleString("en-US");
return (
<p>Freshly server-rendered {now}</p>
);
}Freshly server-rendered 6/21/2026, 3:04:35 PM
Most of your page is static HTML. Islands are the small, interactive parts that get hydrated with JavaScript. You choose exactly what runs on the client.
Built on Preact and Signals, so islands are tiny and reactive out of the box.
Learn more about islandsimport { useSignal } from "@preact/signals";
export default function Counter(props) {
const count = useSignal(props.start);
return (
<div>
<h3>Interactive island</h3>
<p>The server supplied the initial value of {props.start}.</p>
<div>
<button onClick={() => count.value -= 1}>-</button>
<div>{count}</div>
<button onClick={() => count.value += 1}>+</button>
</div>
</div>
);
}The server supplied the initial value of 3.
Handle submissions server-side with standard Request and FormData. No client-side state management, no serialization headaches. Progressive enhancement comes free.
Routes and forms in Freshimport { handler } from "./$index.ts";
export const handlers = handler({
async POST(ctx) {
const form = await ctx.req.formData();
const treat = form.get("treat");
await db.votes.insert({ treat });
return ctx.redirect("/thanks", 303);
},
});Click a link or submit a form and Fresh replaces just the parts of the page that need to change. No full reload, no client-side routing library. The browser navigation UI still works: address bar, back and forward buttons, loading indicator.
Learn more about Partialsimport { handler, page } from "./$[id].ts";
import { Partial } from "fresh/runtime";
export const handlers = handler({
async GET(ctx) {
const content = await loadDoc(ctx.params.id);
return { data: { content } };
},
});
export default page(({ data }) => (
<div f-client-nav>
<aside>
<a href="/docs/introduction">Introduction</a>
<a href="/docs/routing">Routing</a>
<a href="/docs/islands">Islands</a>
</aside>
<main>
<Partial name="content">
{data.content}
</Partial>
</main>
</div>
));Pick a topic from the menu.
Set titles, meta tags, stylesheets, and scripts from any page or island. Fresh hoists them into the document head for you.
<Head>
<title>My Page</title>
<meta name="description"
content="..." />
</Head>Define GET, POST, DELETE, or any HTTP method as a named handler on your route, with full type safety.
export const handlers = handler({
GET(ctx) { /* ... */ },
POST(ctx) { /* ... */ },
DELETE(ctx) { /* ... */ },
});Generated $ helpers give you typed ctx, params, and props.data inferred from the actual handler. No manual interfaces.
import { handler, page } from
"./$[id].ts";
export const handlers = handler({
GET(ctx) {
return { data: ctx.params.id };
},
});Drop a _layout.tsx into any folder under routes/. Fresh composes the layouts outermost-first, automatically.
import { layout } from
"./$_layout.ts";
export default layout(
({ Component }) => (
<div class="app">
<Component />
</div>
),
);Wire onClick into server-rendered HTML with serializable handlers. No island required. The surrounding markup stays static.
import { add } from "fresh/events";
<button onClick={add(count, 1)}>
+
</button>Built on Vite. Instant dev server, fast HMR with Preact Fast Refresh, and full Vite plugin support.
import { defineConfig } from "vite";
import { fresh } from "fresh/vite";
export default defineConfig({
plugins: [fresh()],
});Drop a file in routes/, get a URL. Dynamic params via [id].tsx.
Chain auth, logging, or any logic before your routes run.
Preact Signals power reactive state inside islands and even on the static page.
Nitro builds for Node, Deno Deploy, Cloudflare Workers, containers, and more.
A single _error.tsx renders 404s, 405s, and any thrown error.
Swap regions of the page during navigation, with no full reload.
Fresh is the secret sauce behind production-grade, enterprise-ready software like Deco.cx, Brazil's top eCommerce platform

“The team also used Fresh, a next-gen Deno-native full stack web framework that sends zero JavaScript to the client, for its modern developer experience and snappy performance…
This stack unlocked 5x faster page load speeds and a 30% jump in conversion rates for their clients.”
Fresh builds with Nitro and runs anywhere Nitro does. Node, Deno, Cloudflare Workers, containers, or a static export for a CDN. Pick a host and deploy.
No custom runtime, no fork of the standard library, no host-specific entry file. The same project ships to all of them.
Get startedJump right in and build your website with Fresh. Learn everything you need to know in seconds.
Get started