Last Updated: November 21, 2025
Getting Started
deno run -A -r https://fresh.deno.dev
Create new Fresh project
deno task start
Start development server
deno task build
Build for production
No build step required
Fresh runs directly without bundling
Zero config
Works out of the box
File-based routing
Routes defined by file structure
Route Structure
routes/index.tsx
Home page at /
routes/about.tsx
About page at /about
routes/blog/[slug].tsx
Dynamic route with parameter
routes/api/users.ts
API endpoint at /api/users
routes/_middleware.ts
Middleware for all routes
routes/_app.tsx
Root component wrapper
routes/_404.tsx
Custom 404 page
routes/_500.tsx
Custom error page
Islands Architecture
islands/Counter.tsx
Interactive island component
import Counter from "../islands/Counter.tsx"
Import island in route
<Counter />
Use island (hydrated on client)
Zero JS by default
Pages ship no JavaScript unless islands used
Selective hydration
Only islands get client-side JS
import { useState } from "preact/hooks"
Use hooks in islands
export default function Island() { ... }
Export default function from island
Handlers & Data Fetching
export const handler = { GET(req, ctx) { ... } }
GET request handler
export const handler = { POST(req, ctx) { ... } }
POST request handler
ctx.params.slug
Access route parameters
ctx.render(data)
Render page with data
export default function Page({ data }) { ... }
Receive data in component
return new Response(JSON.stringify(data))
Return JSON response
return ctx.renderNotFound()
Render 404 page
await req.json()
Parse JSON request body
await req.formData()
Parse form data
Middleware
export const handler = [middleware1, middleware2, finalHandler]
Chain multiple middleware
export async function handler(req, ctx) { ... return await ctx.next() }
Middleware pattern
ctx.state.user = user
Set state in middleware
ctx.state.user
Access state in handler
Authentication middleware
Check auth before routes
Logging middleware
Log requests
Static Files
static/logo.png
Serve at /logo.png
static/css/styles.css
Serve at /css/styles.css
<img src="/logo.png" />
Reference static assets
Automatic compression
Brotli and gzip compression
Head & SEO
import { Head } from "$fresh/runtime.ts"
Import Head component
<Head><title>Page Title</title></Head>
Set page title
<meta name="description" content="..." />
Add meta tags
<link rel="stylesheet" href="/styles.css" />
Add stylesheets
Plugins
import twindPlugin from "$fresh/plugins/twind.ts"
Import Twind CSS plugin
plugins: [twindPlugin(twindConfig)]
Register plugin in fresh.config.ts
Custom plugins
Create custom Fresh plugins
UnoCSS plugin
Alternative CSS framework
Deployment
Deploy to Deno Deploy
One-click deployment
GitHub integration
Auto-deploy on push
Edge computing
Deploy globally on edge
No build step
Direct deployment
Pro Tip:
Fresh ships zero JavaScript to the browser by default! Only islands are hydrated. Use islands sparingly for truly interactive components. Take advantage of file-based routing and server-side rendering for blazing fast page loads. Deploy to Deno Deploy for edge computing!