stackademic

The leading education platform for anyone with an interest in software development.

Route Handlers

Build custom HTTP endpoints in the App Router using Web Request and Response APIs

Overview

Route Handlers define API endpoints inside the App Router using a route.ts file. They export functions named after HTTP methods (GET, POST, etc.) and use the standard Web Request and Response objects. Use them for webhooks, third-party integrations, or JSON APIs consumed by clients.

Syntax / Usage

Create app/api/<name>/route.ts and export one function per HTTP method. Handlers receive a Request and can read params from the second argument.

// app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
  const query = request.nextUrl.searchParams.get('q')
  const posts = await db.post.findMany({ where: { title: { contains: query } } })
  return NextResponse.json(posts)
}

export async function POST(request: NextRequest) {
  const body = await request.json()
  const post = await db.post.create({ data: body })
  return NextResponse.json(post, { status: 201 })
}

Examples

Read a dynamic segment via the typed params promise:

// app/api/posts/[id]/route.ts
export async function GET(
  _request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params
  const post = await db.post.findUnique({ where: { id } })
  if (!post) return new Response('Not found', { status: 404 })
  return Response.json(post)
}

Control caching — handlers are dynamic by default; opt into static caching:

// app/api/config/route.ts
export const dynamic = 'force-static'

export async function GET() {
  return Response.json({ theme: 'dark' })
}

Common Mistakes

  • Defining a Route Handler and a page.tsx in the same segment folder (conflict)
  • Forgetting to await request.json() before reading the body
  • Assuming GET handlers are always cached — they are dynamic when reading request data
  • Returning a plain object instead of a Response/NextResponse
  • Not awaiting the params promise in newer App Router versions

See Also

nextjs-server-actions api-routes nextjs-caching