This skill should be used when the user asks to "create an API route", "add an endpoint", "build a REST API", "handle POST requests", "create route handlers", "stream responses", or needs guidance on Next.js API development in the App Router.
View on GitHubdavepoon/buildwithclaude
nextjs-expert
January 16, 2026
Select agents to install to:
npx add-skill https://github.com/davepoon/buildwithclaude/blob/main/plugins/nextjs-expert/skills/route-handlers/SKILL.md -a claude-code --skill route-handlersInstallation paths:
.claude/skills/route-handlers/# Next.js Route Handlers
## Overview
Route Handlers allow you to create API endpoints using the Web Request and Response APIs. They're defined in `route.ts` files within the `app` directory.
## Basic Structure
### File Convention
Route handlers use `route.ts` (or `route.js`):
```
app/
├── api/
│ ├── users/
│ │ └── route.ts # /api/users
│ └── posts/
│ ├── route.ts # /api/posts
│ └── [id]/
│ └── route.ts # /api/posts/:id
```
### HTTP Methods
Export functions named after HTTP methods:
```tsx
// app/api/users/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
const users = await db.user.findMany()
return NextResponse.json(users)
}
export async function POST(request: Request) {
const body = await request.json()
const user = await db.user.create({ data: body })
return NextResponse.json(user, { status: 201 })
}
```
Supported methods: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`
## Request Handling
### Reading Request Body
```tsx
export async function POST(request: Request) {
// JSON body
const json = await request.json()
// Form data
const formData = await request.formData()
const name = formData.get('name')
// Text body
const text = await request.text()
return NextResponse.json({ received: true })
}
```
### URL Parameters
Dynamic route parameters:
```tsx
// app/api/posts/[id]/route.ts
interface RouteContext {
params: Promise<{ id: string }>
}
export async function GET(
request: Request,
context: RouteContext
) {
const { id } = await context.params
const post = await db.post.findUnique({ where: { id } })
if (!post) {
return NextResponse.json(
{ error: 'Not found' },
{ status: 404 }
)
}
return NextResponse.json(post)
}
```
### Query Parameters
```tsx
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const page = searchParams.get('page') ?? '1'
const limit