# Static and server rendering in Astro

Astro supports two output modes, and your choice affects how (and when) content from Sanity reaches your site.

## Static generation (default)

Astro renders all pages to HTML at build time. Every GROQ query runs once during the build, and the resulting HTML files are served as static assets.

**astro.config.mjs**

```typescript
import sanity from '@sanity/astro'
import { defineConfig } from 'astro/config'

export default defineConfig({
  integrations: [
    sanity({
      projectId: 'your-project-id',
      dataset: 'production',
      apiVersion: '2026-03-01',
      useCdn: false, // Fetch fresh data at build time
    }),
  ],
})
```

Static generation is the right choice when content doesn't change frequently and you can afford a short delay between publishing and the site updating. This includes most blogs, marketing sites, portfolios, and documentation.

### Triggering rebuilds on content changes

Static sites need a rebuild to reflect content changes. The most common approach is a webhook that triggers your hosting platform's build process. Go to your project at sanity.io/manage, navigate to API > Webhooks, and create a webhook pointing to your hosting platform's build hook URL.

### Setting useCdn for static builds

Set `useCdn: false` for static builds. Since queries only run at build time, you want the freshest data from the Content Lake, not a potentially stale CDN cache.

## Server-side rendering

In server mode, pages render on every request. GROQ queries run at request time, so content changes appear on the next page load without a rebuild.

**astro.config.mjs**

```typescript
import sanity from '@sanity/astro'
import vercel from '@astrojs/vercel'
import { defineConfig } from 'astro/config'

export default defineConfig({
  output: 'server',
  adapter: vercel(),
  integrations: [
    sanity({
      projectId: 'your-project-id',
      dataset: 'production',
      apiVersion: '2026-03-01',
      useCdn: false, // Required for draft content; set to true for published-only
    }),
  ],
})
```

Server rendering requires a deployment adapter that matches your hosting platform. Server rendering is necessary when you need Visual Editing, draft previews, personalized content, or frequent content updates. Set `useCdn: false` when using the `drafts` perspective for visual editing or previews. For pages that only serve published content, `useCdn: true` provides faster responses from the Sanity CDN.

## Mixing static and server-rendered pages

Both output modes support per-page overrides. In `output: "static"` (the default), all pages are prerendered at build time. To opt individual pages into server rendering, add `export const prerender = false` to the page's frontmatter. In `output: "server"`, all pages are server-rendered by default. To opt individual pages into static generation, add `export const prerender = true`. An adapter is required for any server-rendered pages, even in static mode.

**src/pages/preview/[slug].astro**

```typescript
---
export const prerender = false

import { loadQuery } from '../../lib/load-query'

const { data: post } = await loadQuery({
  query: `*[_type == "post" && slug.current == $slug][0]`,
  params: { slug: Astro.params.slug },
})
---
```

A common pattern for Astro + Sanity projects is static pages for blog posts and landing pages (content changes infrequently), with server-rendered pages for Visual Editing preview routes and API endpoints. This gives you the performance of static generation for the majority of your site, with server rendering only where you need it. Prior to Astro 5, this was handled by a separate `output: "hybrid"` mode, which has been removed.

## Adapters for server rendering

Server rendering requires a deployment adapter that matches your hosting platform:

- `@astrojs/vercel` for Vercel
- `@astrojs/netlify` for Netlify
- `@astrojs/cloudflare` for Cloudflare Workers/Pages
- `@astrojs/node` for self-hosted Node.js

See [Astro’s server adapter documentation](https://docs.astro.build/en/guides/on-demand-rendering/) for more options.

## Content freshness at a glance

In static mode, content is fetched at build time. There is no runtime dependency on the Sanity API, Visual Editing is not supported, any static host works, and performance is the fastest since pages are pre-rendered. In server mode, content is fetched at request time. Every request depends on the Sanity API, Visual Editing is supported, you need a platform with SSR support, and performance depends on CDN caching. Per-page overrides let you mix both approaches within a single output mode.

## Next steps

- If you're building a static site, set up build [functions](https://www.sanity.io/docs/functions/functions-introduction) or webhooks to keep content fresh.
- If you need Visual Editing, configure server rendering and follow the [Visual Editing guide](https://www.sanity.io/docs/visual-editing/astro-visual-editing).
- For most projects, static mode with per-page server rendering for preview routes offers the best balance of performance and flexibility. If most pages need server rendering (for example, a site heavily using Visual Editing), `output: "server"` is the simpler choice since it flips the default.

