Zurück zum Blog
3 Min. LesezeitTutorial

Building Modern Web Apps with Deno Fresh

Learn how to build fast, server-rendered web applications using Fresh, the next-gen web framework for Deno

Building Modern Web Apps with Deno Fresh

Fresh is a next-generation web framework for Deno that embraces server-side rendering and minimal client-side JavaScript. If you've worked with frameworks like Next.js or Remix, Fresh will feel familiar while offering unique advantages.

What Makes Fresh Different?

Islands Architecture

Fresh uses the "islands architecture" pattern - only interactive components (islands) ship JavaScript to the client. Static content stays static, dramatically reducing bundle sizes.

// This is a static component - no JS sent to client
export default function Header() {
  return (
    <header>
      <h1>My Site</h1>
    </header>
  );
}
// islands/Counter.tsx - Interactive island
import { useState } from "preact/hooks";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Zero Config

Fresh works out of the box with:

  • TypeScript support
  • Hot module reloading
  • Server-side rendering
  • File-based routing

Lightning Fast

  • No build step required in development
  • Instant page loads with SSR
  • Minimal JavaScript payloads
  • Native ESM support

Core Concepts

File-Based Routing

routes/
  index.tsx         → /
  about.tsx         → /about
  blog/
    index.tsx       → /blog
    [slug].tsx      → /blog/:slug
  api/
    posts.ts        → /api/posts

Route Handlers

Fresh routes export handlers for different HTTP methods:

import { Handlers, PageProps } from "fresh";

export const handler: Handlers = {
  async GET(req, ctx) {
    const posts = await fetchPosts();
    return ctx.render({ posts });
  },
};

export default function BlogPage({ data }: PageProps) {
  return (
    <div>
      {data.posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  );
}

Middleware

Add middleware for auth, logging, etc.:

// routes/_middleware.ts
import { MiddlewareHandler } from "fresh";

export const handler: MiddlewareHandler[] = [
  async (req, ctx) => {
    // Run before route handler
    const start = Date.now();
    const resp = await ctx.next();
    const ms = Date.now() - start;
    resp.headers.set("X-Response-Time", `${ms}ms`);
    return resp;
  },
];

Building a Real App

Here's a simple blog with Fresh:

// routes/blog/[slug].tsx
import { Handlers, PageProps } from "fresh";
import { extract } from "@std/front-matter";

interface Post {
  slug: string;
  title: string;
  content: string;
}

export const handler: Handlers<Post> = {
  async GET(_req, ctx) {
    const { slug } = ctx.params;
    const text = await Deno.readTextFile(`./content/${slug}.md`);
    const { attrs, body } = extract(text);

    return ctx.render({
      slug,
      title: attrs.title,
      content: body,
    });
  },
};

export default function BlogPost({ data }: PageProps<Post>) {
  return (
    <article>
      <h1>{data.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: data.content }} />
    </article>
  );
}

Performance Benefits

Fresh's approach yields impressive results:

  • Lighthouse scores: 100 across the board
  • Time to Interactive: < 100ms
  • Bundle size: Only islands are shipped as JS
  • SEO: Perfect - everything is server-rendered

Conclusion

Fresh represents a paradigm shift in web development - away from heavy client-side frameworks toward lean, server-rendered applications. With its islands architecture and zero-config approach, Fresh makes it easy to build fast, modern web apps.

Try Fresh for your next project and experience the difference!

👨‍💻

Jordan Patel

Webentwickler & Technologie-Enthusiast