Next.js lets you create API endpoints inside your project using Route Handlers. They live alongside your pages in the app/ directory.

Creating a Route Handler

A route.ts file exports HTTP method functions:

  app/api/hello/route.ts  → GET /api/hello
  
  // app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
    return NextResponse.json({ message: 'Hello from Next.js API!' });
}
  

Supported HTTP Methods

Export named functions for each method:

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

export async function GET() {
    const items = await db.item.findMany();
    return NextResponse.json(items);
}

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

Supported exports: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.

Dynamic Route Handlers

  app/api/users/[id]/route.ts  → /api/users/42
  
  import { NextRequest, NextResponse } from 'next/server';

export async function GET(
    request: NextRequest,
    { params }: { params: Promise<{ id: string }> }
) {
    const { id } = await params;
    const user = await db.user.findUnique({ where: { id } });

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

    return NextResponse.json(user);
}

export async function DELETE(
    request: NextRequest,
    { params }: { params: Promise<{ id: string }> }
) {
    const { id } = await params;
    await db.user.delete({ where: { id } });
    return new NextResponse(null, { status: 204 });
}
  

Reading Request Data

  export async function POST(request: NextRequest) {
    const body = await request.json();                              // JSON body
    const query = request.nextUrl.searchParams.get('q');            // ?q=hello
    const authHeader = request.headers.get('authorization');        // Headers
    const name = (await request.formData()).get('name');            // Form data

    return NextResponse.json({ received: body });
}
  

Response Helpers

  return NextResponse.json({ data: 'value' });
return NextResponse.json({ error: 'Bad request' }, { status: 400 });
return NextResponse.redirect(new URL('/login', request.url));

const response = NextResponse.json({ success: true });
response.cookies.set('token', 'abc123', { httpOnly: true });
return response;
  

Route Handlers vs Server Actions

Route Handlers Server Actions
REST API endpoints Form mutations
Called by external clients Called from your UI
Webhooks, mobile apps Create, update, delete forms

Use Route Handlers when you need a public API. Use Server Actions for form submissions within your app.

Edge Runtime

Run handlers on the Edge for lower latency:

  export const runtime = 'edge';

export async function GET() {
    return NextResponse.json({ region: process.env.VERCEL_REGION });
}
  

Next: intercept requests with middleware for auth and redirects.