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
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 });
});
deno run --allow-net server.ts
Fresh Framework
deno run -A -r https://fresh.deno.dev my-app
cd my-app
deno task start
// 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>
);
}
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>
);
}
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;
}
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(),
});
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);
});
deno test
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)