Route Handlers (API Routes)
Route Handlers are the App Router's way of building API endpoints. Instead of returning JSX, a route.ts file exports one function per HTTP method — GET, POST, PUT, PATCH, DELETE, and so on — and Next.js wires each one up to that route's URL.
A basic GET handler
// app/api/posts/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const posts = await db.post.findMany({
orderBy: { createdAt: 'desc' },
})
return NextResponse.json(posts)
}This creates a real HTTP endpoint at /api/posts. It can be called from a Client Component with fetch, from an external service, from a mobile app, or from any other client that can make an HTTP request — unlike a Server Action, which is only callable from within your own Next.js app.
Reading dynamic segments, query params, and the request body
// app/api/posts/[slug]/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(
request: NextRequest,
{ params }: { params: { slug: string } },
) {
const post = await db.post.findUnique({ where: { slug: params.slug } })
if (!post) {
return NextResponse.json({ error: 'Not found' }, { status: 404 })
}
return NextResponse.json(post)
}
export async function POST(request: NextRequest) {
const body = await request.json()
const searchParams = request.nextUrl.searchParams
const draft = searchParams.get('draft') === 'true'
const post = await db.post.create({
data: { title: body.title, content: body.content, draft },
})
return NextResponse.json(post, { status: 201 })
}Caching behavior
GET Route Handlers can be cached similarly to fetch, using the same route segment configuration exports. By default, a GET handler with no dynamic APIs (cookies, headers, request.url search params) used inside it can be statically evaluated; using any of those, or exporting dynamic = 'force-dynamic', makes it render per request.
export const revalidate = 3600 // cache this GET handler's response for up to an hour
Route Handlers vs. Server Actions
Both let server-side code run in response to something the client does, but they solve different problems. Server Actions are the natural choice for mutations triggered from your own app's forms and components. Route Handlers are the natural choice whenever you need a real, addressable HTTP endpoint.
Route Handlers | Server Actions | |
|---|---|---|
Callable by | Any HTTP client (browser, mobile app, third party, webhook) | Only your own Next.js app |
Defined in | route.ts, one export per HTTP method | A function marked "use server" |
Typical use case | Public/external APIs, webhooks, custom auth callbacks, streaming responses | Form submissions, mutations from your own components |
Invocation from a form | Requires manual fetch + client-side wiring | Pass directly as a form’s action prop |
Returns | A Response/NextResponse object you construct | Whatever value your function returns, used directly in React |
Common use cases for Route Handlers
Webhooks from third-party services (payment providers, CMS platforms) that POST to a fixed URL.
A public API that external clients or a separate frontend consume.
OAuth or auth-provider callback URLs that need to run custom server logic.
Streaming responses, such as server-sent events or proxying a streaming AI response.
Generating non-HTML output at a URL, like an RSS feed, a sitemap, or an image.