komal.nakrani
Browse Themes
ThemesCategoriesDocsBlogTips & Tricks
Server Rendering••By Komal Nakrani

Astro Prerender: Mixing Static and On-Demand Pages

Mix static and server-rendered pages in Astro with export const prerender. Keep output static and opt pages out, or use output server and opt pages back in.

#Astro#SSR#Prerender#Rendering

To mix static and on-demand pages in Astro, install an adapter and use export const prerender per page. With the default output: 'static', every page is prerendered at build time, and export const prerender = false makes a single page render on each request. With output: 'server', it’s the other way round: pages render on request, and export const prerender = true makes a page static.

Key Takeaways

  • An adapter is required for any on-demand page.
  • Mostly static site: keep output: 'static', add prerender = false where needed.
  • Mostly dynamic site: output: 'server', add prerender = true to static pages.
  • Endpoints follow the same rule.

1. Add an adapter

npx astro add netlify   # or cloudflare, vercel, node

This installs the adapter and sets adapter in astro.config.mjs. Without one, a page with prerender = false fails the build, because there’s nothing to run it.

2a. Mostly static: opt pages out

Keep the default output:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';

export default defineConfig({
  adapter: netlify(),
  // output: 'static' is the default
});

Mark the dynamic pages:

---
// src/pages/account.astro
export const prerender = false;

const session = Astro.cookies.get('session')?.value;
if (!session) return Astro.redirect('/login/');
---
<h1>Your account</h1>

Endpoints work the same way:

// src/pages/api/stock.json.ts
export const prerender = false;

export async function GET({ url }) {
  const sku = url.searchParams.get('sku');
  const stock = await getStock(sku);
  return Response.json({ sku, stock });
}

Everything else is still built to static HTML and served from the CDN.

2b. Mostly dynamic: opt pages in

export default defineConfig({
  output: 'server',
  adapter: netlify(),
});
---
// src/pages/about.astro
export const prerender = true;
---
<h1>About us</h1>

Prerendered pages in server mode can still use getStaticPaths() for dynamic routes.

Which pages should be on demand?

Make a page on-demand when it:

  • reads cookies or headers (accounts, carts, auth-gated pages),
  • shows data that must be current to the second (stock, prices, availability),
  • handles form posts with a full page response,
  • has a URL space you can’t list at build time (search results).

Keep it static if the content is the same for everyone and a rebuild on change is fast enough. That covers most content.

A third option: server islands

If only one component on a page is dynamic, you don’t need to make the whole page on-demand. Keep the page static and defer the component:

<CartCount server:defer>
  <span slot="fallback">0</span>
</CartCount>

The page is served from the CDN; CartCount renders on the server per request. This still needs an adapter.

Gotchas

Astro.request.headers on static pages. Prerendered pages run at build time, so there’s no real request. Reading headers or cookies there returns nothing useful, and Astro warns about it.

Middleware runs at build time for static pages. Logic that depends on cookies only works on on-demand routes.

Dynamic config values. prerender must be a literal true or false, so Astro can read it at build time. You can’t compute it from an environment variable at runtime. To set it per route in bulk, use an integration with the astro:route:setup hook.

Hosting cost. On-demand pages run as functions or workers. They’re cheap at low traffic, but they aren’t free the way static files usually are. Cache responses where you can:

---
export const prerender = false;
Astro.response.headers.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=600');
---

The Astro SSR guide goes further into adapters, server islands, actions and sessions, and the Astro deploy guide compares the hosts these adapters target. The Astro configuration docs show where output and adapter go in a theme, and the on-demand rendering docs are the reference.

FAQ

What happened to output: ‘hybrid’ in Astro?

It was removed in Astro 5. The 'static' output now supports on-demand pages directly, so output: 'static' with prerender = false on individual pages is the replacement.

Can I use prerender = false without an adapter?

No. The build fails with an error asking you to add an adapter, because on-demand pages need a server runtime.