Skip to content

Endpoints & API Routes

Not every route renders HTML. A file in src/pages/ with a .ts (or .js) extension is an API endpoint: instead of a template, it exports functions named after HTTP methods (GET, POST, PUT, DELETE) that each return a standard Response.

src/pages/api/health.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = () => {
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};

GET /api/health now returns JSON. The APIRoute type gives you a typed context argument and a Response return — the same web-standard shape as everywhere else in Astro.

The handler receives a context with the request, params, cookies, and more:

src/pages/api/users/[id].ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ params }) => {
const user = await db.users.find(params.id); // [id] from the path
if (!user) return new Response('Not found', { status: 404 });
return Response.json(user); // shorthand JSON response
};
export const POST: APIRoute = async ({ request }) => {
const body = await request.json(); // parse the request body
const created = await db.users.create(body);
return Response.json(created, { status: 201 });
};
flowchart LR
  req["GET or POST /api/..."] --> handler["exported handler
(GET / POST / ...)"]
  handler --> read["read params, request body, cookies"]
  read --> resp["return a Response
(JSON, file, status)"]
An endpoint maps a method to a Response

Like pages, endpoints can be built once or run per request:

  • Static — with output: 'static', a GET endpoint runs at build time and its Response body is written to a file. Great for generating a rss.xml, a sitemap, or a static JSON API that doesn’t change per request. (Static endpoints only support GET.)
  • On-demand — add export const prerender = false (and an adapter) to run the endpoint per request, enabling POST/PUT/DELETE, request bodies, and live data.
// A dynamic endpoint that handles form posts:
export const prerender = false;

Both run server code, but they solve different problems:

  • An endpoint is a raw HTTP route you design yourself — you own the URL, method, status codes, and response shape. Reach for it for webhooks, third-party integrations, file downloads, or a public REST/JSON API.
  • An Action (next lesson) is a type-safe function you call from your own client code with automatic input validation — no URL or Response plumbing. Reach for it for your app’s own mutations and forms.

Rule of thumb: public/external contract → endpoint; internal app logic called from your own frontend → Action.

How do you define an API endpoint in Astro?
A static (build-time) endpoint supports which method(s)?
When should you use an Action instead of an endpoint?
What does an endpoint handler return?