devnotes.

API Routes: Route Handlers

What is a Route Handler?

A route.ts (or .js) file inside app/ defines a backend API endpoint instead of a page. It exports functions named after HTTP methods.

// app/api/students/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';

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

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

This creates a real HTTP endpoint at /api/students that any client — your own frontend, a mobile app, or a third party — can call.

Dynamic route params in a handler

// app/api/students/[id]/route.ts
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  const student = await db.students.findUnique({ where: { id: Number(id) } });
  if (!student) {
    return NextResponse.json({ error: 'Not found' }, { status: 404 });
  }
  return NextResponse.json(student);
}

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

Reading query parameters and headers

export async function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const department = searchParams.get('department'); // /api/students?department=CSE

  const authHeader = request.headers.get('authorization');

  const students = await db.students.findMany({
    where: department ? { department } : undefined,
  });
  return NextResponse.json(students);
}

Route Handlers vs Server Actions — which to use?

Route HandlerServer Action
Best forPublic APIs, webhooks, third-party consumers, non-Next.js clientsMutations triggered from your own UI (forms, buttons)
Called fromAny HTTP client (fetch, curl, mobile app)Directly from React components as a function
URL exposedYes, a real REST endpointNo separate URL — invoked via a framework-generated action id

Use a Route Handler when you need an endpoint external systems can call (a webhook receiver, a public API, a mobile app backend). Use a Server Action when the only caller is your own Next.js UI.

Next.js Route Handlers — Building API Endpoints | DevNotes