Fresh is Deno's answer to Next.js. No build step, no bundler config, no node_modules. Just write TypeScript and deploy.
What is Fresh?
Fresh is a full-stack web framework for Deno. It uses islands architecture (like Astro) — server-renders everything by default and only sends JavaScript for interactive components.
Why Fresh Is Refreshing
1. No Build Step
deno task start
# That's it. No webpack, no Vite, no esbuild config.
# TypeScript, JSX, CSS — all handled automatically.
2. Islands Architecture
// routes/index.tsx — server-rendered, zero JS
export default function Home() {
return (
<div>
<h1>Welcome</h1>
<p>This ships zero JavaScript.</p>
{/* Only THIS component sends JS to the browser */}
<Counter start={0} />
</div>
);
}
// islands/Counter.tsx — this IS the island (client-side JS)
import { useSignal } from "@preact/signals";
export default function Counter({ start }: { start: number }) {
const count = useSignal(start);
return (
<button onClick={() => count.value++}>
Count: {count}
</button>
);
}
3. File-Based Routing
routes/
├── index.tsx → /
├── about.tsx → /about
├── blog/
│ ├── index.tsx → /blog
│ └── [slug].tsx → /blog/:slug
├── api/
│ └── users.ts → /api/users
└── _layout.tsx → Layout wrapper
4. Server-Side Data Loading
// routes/blog/[slug].tsx
import { Handlers, PageProps } from "$fresh/server.ts";
interface Post {
title: string;
content: string;
}
export const handler: Handlers<Post> = {
async GET(req, ctx) {
const post = await db.posts.findOne({ slug: ctx.params.slug });
if (!post) return ctx.renderNotFound();
return ctx.render(post);
},
};
export default function BlogPost({ data }: PageProps<Post>) {
return (
<article>
<h1>{data.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.content }} />
</article>
);
}
5. Form Handling
export const handler: Handlers = {
async POST(req, ctx) {
const form = await req.formData();
const email = form.get("email") as string;
await subscribe(email);
return new Response(null, {
status: 303,
headers: { Location: "/thanks" },
});
},
};
export default function Subscribe() {
return (
<form method="POST">
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</form>
);
}
6. Deploy to Deno Deploy (Free)
# Install deployctl
deno install -A jsr:@deno/deployctl
# Deploy
deployctl deploy
Edge deployment in 35+ regions. Free tier includes 1M requests/month.
Fresh vs Next.js vs Astro
| Fresh | Next.js | Astro | |
|---|---|---|---|
| Runtime | Deno | Node.js | Node.js |
| Build step | None | Required | Required |
| Default JS | Islands only | React runtime | Zero |
| UI library | Preact | React | Any |
| Config files | Zero | next.config.js | astro.config.mjs |
| Deploy | Deno Deploy | Vercel | Any |
Getting Started
deno run -A -r https://fresh.deno.dev my-project
cd my-project
deno task start
The Bottom Line
Fresh is the simplest full-stack framework. No build, no config, no node_modules. Write TypeScript, ship HTML with minimal JS, deploy to the edge.
Need data tools? I build scraping solutions. Check my Apify actors or email spinov001@gmail.com.
Top comments (0)