Files
EapilSkillMarket/plugins/codex/plugins/next-skills/skills/next-best-practices/route-handlers.md
T
KeyInfo Bot 104a4b101d Publish Next.js Agent Skills
Constraint: Upstream next-skills is a multi-skill collection under skills/*/SKILL.md.\nRejected: Copy upstream README badge/install docs | marketplace README stays install-focused and plugin content avoids nonessential images.\nConfidence: high\nScope-risk: moderate\nDirective: Use skill-collection with skillsPath for repositories organized as direct child skill directories.\nTested: python scripts/validate_marketplace.py; python /Users/eapil/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py plugins/codex/plugins/next-skills; temp CODEX_HOME codex plugin marketplace add/list/add plus debug prompt-input.\nNot-tested: scripts/sync_external_plugins.ps1 execution because pwsh/powershell is not installed.
2026-06-15 16:30:27 +08:00

3.2 KiB

Route Handlers

Create API endpoints with route.ts files.

Basic Usage

// app/api/users/route.ts
export async function GET() {
  const users = await getUsers()
  return Response.json(users)
}

export async function POST(request: Request) {
  const body = await request.json()
  const user = await createUser(body)
  return Response.json(user, { status: 201 })
}

Supported Methods

GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

GET Handler Conflicts with page.tsx

A route.ts and page.tsx cannot coexist in the same folder.

app/
├── api/
│   └── users/
│       └── route.ts    # /api/users
└── users/
    ├── page.tsx        # /users (page)
    └── route.ts        # Warning: Conflicts with page.tsx!

If you need both a page and an API at the same path, use different paths:

app/
├── users/
│   └── page.tsx        # /users (page)
└── api/
    └── users/
        └── route.ts    # /api/users (API)

Environment Behavior

Route handlers run in a Server Component-like environment:

  • Yes: Can use async/await
  • Yes: Can access cookies(), headers()
  • Yes: Can use Node.js APIs
  • No: Cannot use React hooks
  • No: Cannot use React DOM APIs
  • No: Cannot use browser APIs
// Bad: This won't work - no React DOM in route handlers
import { renderToString } from 'react-dom/server'

export async function GET() {
  const html = renderToString(<Component />)  // Error!
  return new Response(html)
}

Dynamic Route Handlers

// app/api/users/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params
  const user = await getUser(id)

  if (!user) {
    return Response.json({ error: 'Not found' }, { status: 404 })
  }

  return Response.json(user)
}

Request Helpers

export async function GET(request: Request) {
  // URL and search params
  const { searchParams } = new URL(request.url)
  const query = searchParams.get('q')

  // Headers
  const authHeader = request.headers.get('authorization')

  // Cookies (Next.js helper)
  const cookieStore = await cookies()
  const token = cookieStore.get('token')

  return Response.json({ query, token })
}

Response Helpers

// JSON response
return Response.json({ data })

// With status
return Response.json({ error: 'Not found' }, { status: 404 })

// With headers
return Response.json(data, {
  headers: {
    'Cache-Control': 'max-age=3600',
  },
})

// Redirect
return Response.redirect(new URL('/login', request.url))

// Stream
return new Response(stream, {
  headers: { 'Content-Type': 'text/event-stream' },
})

When to Use Route Handlers vs Server Actions

Use Case Route Handlers Server Actions
Form submissions No Yes
Data mutations from UI No Yes
Third-party webhooks Yes No
External API consumption Yes No
Public REST API Yes No
File uploads Both work Both work

Prefer Server Actions for mutations triggered from your UI. Use Route Handlers for external integrations and public APIs.