DEV Community

ZNY
ZNY

Posted on

The Complete Guide to Building with Deno 2 in 2026: Fresh Framework and Full-Stack Development

The Complete Guide to Building with Deno 2 in 2026: Fresh Framework and Full-Stack Development

Deno 2.0 stabilized in late 2025, finally addressing the Node.js compatibility gap with a full Node.js compatibility layer, npm support, and the Fresh framework for full-stack development. For new projects, Deno 2 offers a cleaner default experience with built-in TypeScript and security-first design.

Here's the practical guide.

Deno 2 vs Node.js

Node.js: npm, CommonJS, lots of security footguns
Deno: ES modules, TypeScript-native, secure by default, built-in testing
Enter fullscreen mode Exit fullscreen mode

Deno 2: Now also supports npm packages and CommonJS.

Basic HTTP Server

// server.ts
Deno.serve({ port: 8000 }, async (request) => {
  const url = new URL(request.url);

  if (url.pathname === "/api/hello") {
    return new Response(JSON.stringify({
      message: "Hello from Deno!",
      version: Deno.version.deno,
    }), {
      headers: { "Content-Type": "application/json" },
    });
  }

  return new Response("Not Found", { status: 404 });
});
Enter fullscreen mode Exit fullscreen mode
deno run --allow-net server.ts
Enter fullscreen mode Exit fullscreen mode

Fresh Framework

deno run -A -r https://fresh.deno.dev my-app
cd my-app
deno task start
Enter fullscreen mode Exit fullscreen mode
// routes/index.tsx
import { PageProps } from "$fresh/server.ts";

export default function Home({ url }: PageProps) {
  return (
    <main>
      <h1>Welcome to Fresh</h1>
      <p>Current path: {url.pathname}</p>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Islands Architecture

// islands/Counter.tsx
import { useState } from "preact/hooks";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

// Use in a page
// routes/index.tsx
import Counter from "../islands/Counter";

export default function Home() {
  return (
    <main>
      <h1>Counter Island Demo</h1>
      <Counter />
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Middleware

// middleware.ts
import { FreshContext } from "$fresh/server.ts";

export async function handler(
  req: Request,
  ctx: FreshContext,
) {
  // Add custom header
  const response = await ctx.next();
  response.headers.set("X-Custom-Header", "from-deno");

  // Add timing
  const start = Date.now();
  const newResponse = await ctx.next();
  const duration = Date.now() - start;

  newResponse.headers.set("X-Response-Time", `${duration}ms`);
  return newResponse;
}
Enter fullscreen mode Exit fullscreen mode

Database with Drizzle

// db/schema.ts
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
  email: text("email").notNull(),
  createdAt: timestamp("created_at").defaultNow(),
});
Enter fullscreen mode Exit fullscreen mode

Testing

// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

// math_test.ts
import { assertEquals } from "$std/testing/asserts.ts";
import { add } from "./math.ts";

Deno.test("add should return sum", () => {
  assertEquals(add(2, 3), 5);
});
Enter fullscreen mode Exit fullscreen mode
deno test
Enter fullscreen mode Exit fullscreen mode

This article contains affiliate links. If you sign up through the links above, I may earn a commission at no additional cost to you.

Ready to Build Your Online Business?

Get started with Systeme.io for free — All-in-one platform for building your online business with AI tools.

Top comments (0)