DEV Community

Alex Spinov
Alex Spinov

Posted on

Fresh Has a Free Deno Web Framework — Islands Architecture With Zero Config

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.
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode
// 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. Deploy to Deno Deploy (Free)

# Install deployctl
deno install -A jsr:@deno/deployctl

# Deploy
deployctl deploy
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)