Loading...
Loading...
By continuing to use the platform, you accept the terms of the Privacy Policy and the use of cookies.
Route Handlers (called API Routes in the Pages Router) let you create server-side API endpoints directly in a Next.js application. They are defined in route.ts files inside the app directory.
// app/api/problems/route.ts
import { NextResponse } from 'next/server'
import { db } from '@/lib/db'
export async function GET() {
const problems = await db.problem.findMany()
return NextResponse.json(problems)
}
export async function POST(request: Request) {
const body = await request.json()
const problem = await db.problem.create({
data: body
})
return NextResponse.json(problem, { status: 201 })
}
Each exported method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) handles the corresponding HTTP request.
// app/api/problems/[id]/route.ts
import { NextResponse } from 'next/server'
import { db } from '@/lib/db'
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const problem = await db.problem.findUnique({
where: { id: params.id }
})
if (!problem) {
return NextResponse.json(
{ error: 'Problem not found' },
{ status: 404 }
)
}
return NextResponse.json(problem)
}
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
await db.problem.delete({ where: { id: params.id } })
return new Response(null, { status: 204 })
}
Route Handlers use the standard Web API Request:
// app/api/search/route.ts
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const query = searchParams.get('q')
if (!query) {
return NextResponse.json(
{ error: 'Query parameter required' },
{ status: 400 }
)
}
const results = await db.problem.findMany({
where: { name: { contains: query, mode: 'insensitive' } }
})
return NextResponse.json(results)
}
import { cookies, headers } from 'next/headers'
export async function GET() {
const cookieStore = cookies()
const token = cookieStore.get('session')
const headersList = headers()
const userAgent = headersList.get('user-agent')
return NextResponse.json({ token, userAgent })
}
GET requests that do not read the Request are cached by default:
// Cached (static Route Handler)
export async function GET() {
const data = await fetch('https://api.example.com/data')
return NextResponse.json(data)
}
// Not cached (reads Request)
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
// ...
}
For explicit cache control:
export const dynamic = 'force-dynamic' // always dynamic
export const revalidate = 300 // revalidate after 5 minutes
| Route Handlers | Server Actions | |
|---|---|---|
| Purpose | API endpoints | UI mutations |
| HTTP methods | GET, POST, PUT, DELETE... | POST only |
| Called from | Any client (fetch, curl) | Components only |
| Progressive enhancement | No | Yes (forms) |
When to use which:
Use Server Actions for data mutations from the interface (forms, buttons). Use Route Handlers for public APIs, webhooks, integrations with external services and cases where specific HTTP methods are needed.