Route Handlers
A volunteer is building a phone app for Trailhead and asks for the trail data as JSON. You do not need a separate backend for that. Next.js lets you write API endpoints in the same app folder as your pages, using the same routing rules.
The rule
A
routefile exports HTTP verbs; each takes a Request and returns a Response.
Create route.ts in a folder and export async functions named after the HTTP methods you support: GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS.
// app/api/trails/route.ts → /api/trails
import { getTrails, createTrail } from "@/lib/trails";
export async function GET() {
const trails = await getTrails();
return Response.json(trails);
}
export async function POST(request: Request) {
const body = await request.json();
const trail = await createTrail(body);
return Response.json(trail, { status: 201 });
}Handlers use the standard Web Request and Response objects, the same ones fetch uses. Next.js also offers NextRequest and NextResponse, which extend them with conveniences such as easy cookie access.
Dynamic segments work exactly as for pages. The second argument carries params, which you await:
// app/api/trails/[slug]/route.ts → /api/trails/misty-ridge
import { getTrail } from "@/lib/trails";
export async function GET(
request: Request,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params;
const trail = await getTrail(slug);
if (!trail) return Response.json({ error: "Not found" }, { status: 404 });
return Response.json(trail);
}Rules to remember:
- A method you do not export gets 405 Method Not Allowed.
- A folder can hold a
page.tsxor aroute.ts, not both: one URL cannot be a page and an endpoint at once. That is why APIs usually live underapp/api/. - Route handlers run only on the server, so they can use secrets and databases, like server components.
The shortcut
Translate the request into a path: URL → folder, method → function name. DELETE /api/trails/fox-hollow means the DELETE export in app/api/trails/[slug]/route.ts.
URL to folder
/api/trails/misty-ridge→app/api/trails/[slug]/route.ts.
The trap is returning a plain object: return trail. A handler must return a Response; wrap data with Response.json(...).
Drills
Answer fast — trust the rule.
Which file answers requests to /api/trails?
A client sends PATCH /api/trails but the file exports only GET and POST. What is the response?
How should a GET handler send a list of trails as JSON?
Can app/trails/route.ts and app/trails/page.tsx both exist?
Remember
- A
routefile exports HTTP verbs; each takes aRequestand returns aResponse. - Shortcut: URL → folder, method → function name.
- Trap: return a
Response, not a plain object, and never putroutebesidepage.
