Skip to content

Server-Side Astro

Astro is static by default, but you opt into the server whenever a page needs request-time work — the logged-in user, a form submission, live data, an auth check. The server is a tool you reach for deliberately, not the default substrate.

Everything in this module is about that opt-in: rendering per request, handling requests directly, calling server logic type-safely, and running code before every request.

LessonWhat you’ll learn
SSR & adaptersOn-demand rendering, adapters, and reading the request
Endpoints & API routesAPIRoute handlers that return a Response
ActionsType-safe server functions with defineAction and validation
Middleware & sessionsonRequest, context.locals, and Astro.session
flowchart TB
  req["Incoming request"] --> mw["Middleware onRequest
(runs first, every request)"]
  mw --> page["On-demand page
(prerender false)"]
  mw --> api["API endpoint
(GET/POST handler)"]
  mw --> act["Action handler
(defineAction)"]
  page --> resp["Response"]
  api --> resp
  act --> resp
The server-side surface of Astro
  • On-demand pages render HTML per request, so they can read cookies, the user, and query params.
  • API endpoints are non-HTML routes — return JSON, a file, a webhook reply — as a raw Response.
  • Actions are type-safe server functions you call from the client with validated input, ideal for mutations and forms.
  • Middleware runs before every request, the place for auth, logging, and shared per-request data.
What is Astro’s default, and when do you opt into the server?
Which tool is best for a type-safe server function called from the client with validated input?
Where does middleware run?