Route Handlers (API Routes)
Build real HTTP endpoints inside the app folder. Useful for webhooks, third-party clients and anything that isn't a UI.
Server actions cover most internal mutations, but sometimes you genuinely need an HTTP endpoint — for webhooks, third-party callers, or non-React clients. Route handlers are that.
Where they live
Create a route.js file in any folder under app/ (instead of page.js). The folder's path becomes the URL.
app/api/hello/route.js → GET/POST/etc to /api/hello
app/webhooks/stripe/route.js → /webhooks/stripeExporting HTTP methods
Export a function for each HTTP method you want to handle. They receive a Web Request and return a Web Response:
// app/api/hello/route.js
export async function GET() {
return Response.json({ message: "Hello" });
}
export async function POST(request) {
const body = await request.json();
return Response.json({ echoed: body }, { status: 201 });
}Reading query params and dynamic segments
// app/api/items/[id]/route.js
export async function GET(request, { params }) {
const { id } = await params;
const url = new URL(request.url);
const fields = url.searchParams.get("fields");
return Response.json({ id, fields });
}Caching behavior
By default, GET route handlers are not cached in Next.js 16 — you opt in. The same dynamic/revalidate exports from lesson 12 work here too:
// app/api/posts/route.js
export const revalidate = 60;
export async function GET() {
const posts = await db.post.findMany();
return Response.json(posts);
}POST, PUT, PATCH, DELETE are always dynamic — they perform side effects, so caching wouldn't make sense.
Route handler vs. server action
- Use a **server action** for internal form submissions and mutations from your own UI.
- Use a **route handler** for everything that needs a stable, public HTTP contract.
- Both run on the server. Both can hit your database. Pick the one that fits the caller.
Response objects. That means streaming, redirects, cookies and binary responses all work using the standard Web API.Try it
Turn this Express-style handler into a Next.js route handler at `app/api/echo/route.js`.
Need a hint?
Export a function named after the HTTP method. Read the body with `await request.json()`.
Quiz
Pick the best answer. You only get one shot per question.
1. Which file makes a folder under `app/` an HTTP endpoint instead of a UI page?
2. Are GET route handlers cached by default in Next.js 16?
3. You need to expose a webhook to a third-party service. Which is the right tool?