Three Output Modes — Static, Server, Hybrid
Static vs Server
Astro can build to a folder of static files, run on a Node server, or mix per-page. The `output` config picks the mode.
What you'll learn
- Recognize the three output modes
- Pick the right one for your project
- Understand the per-page prerender flag
By default Astro builds a folder of static files — dist/ —
deployable to any static host. You can switch on a server runtime
for server-rendered pages, or mix both.
Three Modes
output | Behavior |
|---|---|
"static" (default) | All pages pre-rendered at build, deployed as static files |
"server" | All pages rendered on a Node-like server at request time |
"hybrid" (now the default in Astro 4+) | Per-page choice via prerender flag |
In Astro 4+, “hybrid” is the default and the distinction between
hybrid and static mostly comes down to whether you have an
adapter installed.
Setting the Mode
// astro.config.mjs
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
}); Server mode requires an adapter — @astrojs/node,
@astrojs/vercel, @astrojs/netlify, @astrojs/cloudflare. The
adapter targets a specific runtime.
When To Pick Which
| Use case | Mode |
|---|---|
| Marketing site, blog, docs, portfolio | Static |
| Some pages need auth or personalization | Hybrid |
| Every page is user-specific (dashboards, forums) | Server |
| Want full edge / serverless deployment | Server (with edge adapter) |
Per-Page Prerender
In hybrid mode, each page can opt in or out of pre-rendering:
---
// src/pages/dashboard.astro
export const prerender = false; // render at request time, even though others are static
---
<h1>Hello, {Astro.cookies.get("user")?.value}</h1> Or the inverse — server mode but this page is static:
---
export const prerender = true;
---
<h1>Welcome</h1> What Changes In Server Mode
getStaticPathsdoesn’t run (or is ignored on non-prerendered routes)Astro.requestworks (full headers, method, etc.)Astro.url.searchParamsreads the actual request’s query- You can return
new Response(...)directly from a page - Endpoint files (
.ts) become real API routes
Up Next
Mixing static and server pages with prerender.