A `.ts` File in `src/pages/` Is an API Route
Endpoints
Export `GET`, `POST`, etc., from a `.ts` file under `src/pages/`, return a `Response`, and Astro routes requests to it.
What you'll learn
- Author a GET endpoint
- Read query params and the body
- Return JSON or plain text
A .ts (or .js) file in src/pages/ is an endpoint — an
API route, not a page. Export functions named after HTTP methods,
return a Response.
A GET Endpoint
// src/pages/api/hello.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = () => {
return new Response(JSON.stringify({ hello: "world" }), {
headers: { "content-type": "application/json" },
});
}; Visit /api/hello → {"hello":"world"}.
For static builds, endpoints must be marked
export const prerender = false (or the site must be in server
mode), otherwise the endpoint is treated as static and only the
build-time response is shipped.
Reading Query Params
// src/pages/api/search.ts
export const prerender = false;
export const GET: APIRoute = ({ url }) => {
const q = url.searchParams.get("q") ?? "";
return new Response(JSON.stringify({ q, results: [/* ... */] }), {
headers: { "content-type": "application/json" },
});
}; The context ({ url, params, request, cookies, redirect, ... })
is the same as in pages.
POST Endpoint
// src/pages/api/contact.ts
export const prerender = false;
export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
if (!body.email) {
return new Response(JSON.stringify({ error: "email required" }), {
status: 400,
headers: { "content-type": "application/json" },
});
}
await saveContact(body);
return new Response(JSON.stringify({ ok: true }), {
headers: { "content-type": "application/json" },
});
}; Convenience — JSON Response
Astro 4+ exports a Response.json(...) helper from the platform:
return Response.json({ ok: true });
return Response.json({ error: "bad" }, { status: 400 }); Less boilerplate, same result.
Dynamic Endpoint Routes
Brackets work in .ts files too:
// src/pages/api/users/[id].ts
export const GET: APIRoute = async ({ params }) => {
const user = await db.users.findById(params.id);
return Response.json(user);
}; Streaming Responses
You can return a Response with a streaming body — server-sent
events, large NDJSON dumps, etc. The Response API is the same
standard one browsers and Node both implement.
Up Next
A common use of endpoints — handling form submissions.
Forms →