git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/astro-ssr-hybrid" ~/.claude/skills/intense-visions-harness-engineering-astro-ssr-hybrid-89a5eb && rm -rf "$T"
agents/skills/codex/astro-ssr-hybrid/SKILL.mdAstro SSR and Hybrid Rendering
Control rendering mode at the project level and per-page — combine static pre-rendering with server-side dynamic pages using
and adapter configuration.output: 'hybrid'
When to Use
- You need some pages to be server-rendered (authenticated dashboards, personalized content, real-time data) while others stay static
- You are adding authentication, user sessions, or cookie-based personalization to an Astro project
- You want to read
headers,Astro.request
, orAstro.cookies
in a pageAstro.locals - You are selecting an adapter for a deployment target (Vercel, Node.js, Cloudflare)
- You need to understand which features (redirects, cookies,
) are available in SSG vs. SSR modeAstro.params
Instructions
- Set the
field and install an adapter inoutput
:astro.config.mjs
// astro.config.mjs import { defineConfig } from 'astro/config'; import vercel from '@astrojs/vercel/serverless'; export default defineConfig({ output: 'server', // all pages are SSR by default adapter: vercel(), });
Available
output values:
(default) — all pages pre-rendered at build time; no server required'static'
— all pages SSR; a server adapter is required'server'
— all pages static by default; opt specific pages into SSR with'hybrid'prerender = false
- In
mode, opt a page into SSR by exportingoutput: 'hybrid'
:prerender = false
--- // src/pages/dashboard.astro export const prerender = false; // This page is server-rendered const user = Astro.locals.user; if (!user) return Astro.redirect('/login'); const data = await fetchUserData(user.id); --- <h1>Welcome, {user.name}</h1>
- In
mode, opt a page into static pre-rendering by exportingoutput: 'server'
:prerender = true
--- // src/pages/about.astro export const prerender = true; // Pre-render this page at build time --- <h1>About Us</h1>
- Use
to read request data in SSR pages. This is a standardAstro.request
object:Request
--- export const prerender = false; const url = new URL(Astro.request.url); const query = url.searchParams.get('q') ?? ''; const userAgent = Astro.request.headers.get('user-agent'); const clientIp = Astro.clientAddress; // requires adapter support ---
- Read and write cookies with
:Astro.cookies
--- export const prerender = false; // Read a cookie const theme = Astro.cookies.get('theme')?.value ?? 'light'; // Set a cookie Astro.cookies.set('theme', 'dark', { httpOnly: false, secure: true, sameSite: 'lax', maxAge: 60 * 60 * 24 * 365, // 1 year path: '/', }); ---
- Return a redirect from a page with
:Astro.redirect()
--- export const prerender = false; const session = Astro.cookies.get('session')?.value; if (!session) return Astro.redirect('/login', 302); ---
- Install the correct adapter for your deployment target:
# Vercel npx astro add vercel # Node.js (standalone server) npx astro add node # Cloudflare Pages/Workers npx astro add cloudflare # Netlify npx astro add netlify
- For dynamic routes in SSR mode, do not implement
. Astro readsgetStaticPaths()
directly from the request URL:Astro.params
--- // src/pages/blog/[slug].astro export const prerender = false; const { slug } = Astro.params; const post = await fetchPost(slug); if (!post) return Astro.redirect('/404'); --- <article><h1>{post.title}</h1></article>
Details
Astro's rendering model is a spectrum from fully static to fully dynamic. Understanding which mode to use for each page is the key design decision in an Astro SSR project.
When to use each mode:
| Page type | Recommended mode |
|---|---|
| Marketing pages, blog posts, docs | (static) |
| Authenticated dashboards | (SSR) |
| Product pages (semi-static) | + client-side data fetching |
| Search results | (SSR) |
| API endpoints with dynamic data | (SSR) |
| Sitemap, RSS feed | (static) |
vs. output: 'hybrid'
:output: 'server'
Choose
output: 'hybrid' when most of your pages are static and a few need SSR. This is the most common pattern for content sites with authenticated features. Choose output: 'server' for applications where most pages are dynamic (dashboards, SaaS apps).
Adapter selection:
The adapter transforms Astro's SSR output into the format required by the target platform:
— Vercel serverless functions@astrojs/vercel/serverless
— Vercel Edge Functions (limited Node.js API surface)@astrojs/vercel/edge
— standalone Node.js server (requires@astrojs/node
)node src/server.mjs
— Cloudflare Pages / Workers (no Node.js built-ins)@astrojs/cloudflare
— Netlify Functions / Edge Functions@astrojs/netlify
and middleware:Astro.locals
Middleware populates
Astro.locals before the page runs. This is the correct channel for auth state, feature flags, and tenant context. In SSG mode, Astro.locals is available but middleware only runs at build time (not per-request).
Streaming:
Astro supports streaming SSR responses. The page begins streaming HTML to the client before all async data is resolved. Components that are not awaited render as placeholders until their data arrives. This improves Time To First Byte (TTFB) for pages with multiple independent async data sources.
Environment variables in SSR:
Use
import.meta.env.SECRET_API_KEY for server-only secrets. These values are available at build time and runtime in SSR, but are never exposed to the client bundle. Public variables must be prefixed with PUBLIC_ to be accessible in client-side scripts.
Source
https://docs.astro.build/en/guides/server-side-rendering
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.