Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply Next.js best practices for RSC boundaries, async APIs, routing, metadata, and optimization.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
route-handlers.md
1# Route Handlers23Create API endpoints with `route.ts` files.45## Basic Usage67```tsx8// app/api/users/route.ts9export async function GET() {10const users = await getUsers()11return Response.json(users)12}1314export async function POST(request: Request) {15const body = await request.json()16const user = await createUser(body)17return Response.json(user, { status: 201 })18}19```2021## Supported Methods2223`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`2425## GET Handler Conflicts with page.tsx2627**A `route.ts` and `page.tsx` cannot coexist in the same folder.**2829```30app/31├── api/32│ └── users/33│ └── route.ts # /api/users34└── users/35├── page.tsx # /users (page)36└── route.ts # Warning: Conflicts with page.tsx!37```3839If you need both a page and an API at the same path, use different paths:4041```42app/43├── users/44│ └── page.tsx # /users (page)45└── api/46└── users/47└── route.ts # /api/users (API)48```4950## Environment Behavior5152Route handlers run in a **Server Component-like environment**:5354- Yes: Can use `async/await`55- Yes: Can access `cookies()`, `headers()`56- Yes: Can use Node.js APIs57- No: Cannot use React hooks58- No: Cannot use React DOM APIs59- No: Cannot use browser APIs6061```tsx62// Bad: This won't work - no React DOM in route handlers63import { renderToString } from 'react-dom/server'6465export async function GET() {66const html = renderToString(<Component />) // Error!67return new Response(html)68}69```7071## Dynamic Route Handlers7273```tsx74// app/api/users/[id]/route.ts75export async function GET(76request: Request,77{ params }: { params: Promise<{ id: string }> }78) {79const { id } = await params80const user = await getUser(id)8182if (!user) {83return Response.json({ error: 'Not found' }, { status: 404 })84}8586return Response.json(user)87}88```8990## Request Helpers9192```tsx93export async function GET(request: Request) {94// URL and search params95const { searchParams } = new URL(request.url)96const query = searchParams.get('q')9798// Headers99const authHeader = request.headers.get('authorization')100101// Cookies (Next.js helper)102const cookieStore = await cookies()103const token = cookieStore.get('token')104105return Response.json({ query, token })106}107```108109## Response Helpers110111```tsx112// JSON response113return Response.json({ data })114115// With status116return Response.json({ error: 'Not found' }, { status: 404 })117118// With headers119return Response.json(data, {120headers: {121'Cache-Control': 'max-age=3600',122},123})124125// Redirect126return Response.redirect(new URL('/login', request.url))127128// Stream129return new Response(stream, {130headers: { 'Content-Type': 'text/event-stream' },131})132```133134## When to Use Route Handlers vs Server Actions135136| Use Case | Route Handlers | Server Actions |137|----------|----------------|----------------|138| Form submissions | No | Yes |139| Data mutations from UI | No | Yes |140| Third-party webhooks | Yes | No |141| External API consumption | Yes | No |142| Public REST API | Yes | No |143| File uploads | Both work | Both work |144145**Prefer Server Actions** for mutations triggered from your UI.146**Use Route Handlers** for external integrations and public APIs.147