Rendering & Output Modes
Two ways to produce a page’s HTML
Section titled “Two ways to produce a page’s HTML”Astro can render a route’s HTML at two different times, and this choice is central to how you deploy:
- Static (SSG) — the HTML is built once, at build time, and served as a plain file. Fast, cacheable, deployable to any static host or CDN. Perfect for content that’s the same for everyone.
- On-demand (SSR) — the HTML is built per request, on a server, so it can use request-time data (the logged-in user, cookies, query params, live data). Requires a runtime, which means an adapter.
flowchart TB
subgraph static["Static (SSG)"]
b["build time"] --> f["HTML file"] --> cdn["served from CDN"]
end
subgraph ssr["On-demand (SSR)"]
r["each request"] --> srv["server renders HTML"] --> resp["response"]
end The default is static. You opt a project (or a single route) into on-demand rendering when a page genuinely needs per-request data.
Per-route control with prerender
Section titled “Per-route control with prerender”You don’t choose one mode for the whole site. In a server-enabled project, each route decides for itself with export const prerender:
---// A mostly-static site with one dynamic route:export const prerender = false; // render THIS page on demand, per requestconst user = await getUser(Astro.request); // needs the incoming request---<p>Welcome, {user.name}</p>export const prerender = true→ build this route to a static file (even in a server project).export const prerender = false→ render this route on demand (even in a mostly-static project).
This is the powerful middle ground: a site that is 95% static files with a handful of on-demand routes (a dashboard, a form handler), each rendered only when needed. This is often called hybrid rendering.
Adapters: how on-demand runs
Section titled “Adapters: how on-demand runs”Static output needs nothing but a file host. On-demand rendering needs a runtime to execute your server code per request — and that’s where an adapter comes in. You install the adapter for your target platform and set it in the config:
// astro.config.mjs — enabling on-demand rendering on Cloudflareimport { defineConfig } from 'astro/config';import cloudflare from '@astrojs/cloudflare';
export default defineConfig({ adapter: cloudflare(), // or node(), vercel(), netlify()...});The adapter translates Astro’s server rendering into the platform’s format (a Cloudflare Worker, a Node server, a Vercel function). Without an adapter, on-demand features (SSR routes, server islands, Actions endpoints) can’t run — that’s a common first-deploy error: “an adapter is required.”
What the build produces
Section titled “What the build produces”astro build runs your component scripts, renders the HTML, bundles the CSS and any island JavaScript, and writes the output to dist/. For a static site that’s a folder of .html files and assets you can drop on any CDN. For a hybrid/server site, dist/ also contains the server entry the adapter runs. Either way, the browser receives finished HTML plus only the island JS — the foundational promise, delivered by the build.