Next.js API Route Builder

Generate a Next.js API route with method handling and error responses

Build a Next.js App Router route.ts with exported GET and POST handlers, request body parsing, a validation stub, try/catch error handling, and typed NextResponse JSON responses with correct status codes.

Where do App Router route handlers live?

In the Next.js App Router, route handlers go in a file named route.ts inside an app directory folder. The folder path becomes the URL, so app/api/users/route.ts serves /api/users.

A production-shaped Next.js route handler

The App Router replaced pages/api with file-based route handlers: a route.ts file exports one async function per HTTP method. A solid handler parses input, validates it, does its work inside a try/catch, and returns typed JSON with the right status. This builder assembles that structure for the methods you choose.

How it works

The tool generates an app/api/<resource>/route.ts. It imports { NextRequest, NextResponse } from 'next/server'. For each selected method it exports an async function: GET returns a list or item with NextResponse.json(data, { status: 200 }); POST awaits request.json(), runs a validation stub, and returns 201 on success or 400 on bad input; PUT and DELETE follow the same parse-validate-respond pattern. Every handler is wrapped in try/catch, logging the error and returning NextResponse.json({ error }, { status: 500 }) so a thrown exception never leaks a stack trace to the client.

Tips and example

  • Replace the validation stub with a Zod schema (schema.safeParse(body)) for real input checking.
  • Use 201 Created after a successful POST and include the new resource in the body.
  • Keep handlers thin — delegate business logic to a service module so the route stays about HTTP.
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    if (!body?.name) {
      return NextResponse.json({ error: "name is required" }, { status: 400 });
    }
    // TODO: persist the resource
    return NextResponse.json({ id: 1, ...body }, { status: 201 });
  } catch {
    return NextResponse.json({ error: "Invalid request" }, { status: 500 });
  }
}