Creating a Route Handler

route.ts

A route.ts file exports functions named after HTTP methods. It uses the Web Request and Response APIs. A folder cannot have both page.tsx and route.ts.

app/api/products/route.ts

import { prisma } from '@/lib/prisma';

export async function GET() {
  const products = await prisma.product.findMany({ take: 20 });
  return Response.json(products);
}

export async function POST(request: Request) {
  const body = (await request.json()) as { name: string; price: number };
  const product = await prisma.product.create({ data: { ...body, stock: 0 } });
  return Response.json(product, { status: 201 });
}

Example

curl -i -X POST localhost:3000/api/products -H "Content-Type: application/json" -d '{"name":"Clean Code","price":450}'

Example output

HTTP/1.1 201 Created
content-type: application/json

{"id":3,"name":"Clean Code","price":450,"stock":0}

When to Use Route Handlers

NeedUse
Your own UI saves a formServer Action
Your own UI reads dataServer Component (no API needed)
Mobile app or third party calls your APIRoute Handler
Webhooks (Razorpay, Stripe, CMS)Route Handler
Files: CSV export, RSS, imagesRoute Handler

Note: GET handlers are dynamic by default in Next.js 15+. Add export const dynamic = 'force-static' to cache a GET response at build time.

Handlers Are Just Functions

Example

Because they use the standard Web API, you can call a handler directly in a test:

async function GET(request: Request): Promise<Response> {
  const url = new URL(request.url);
  const q = url.searchParams.get('q') ?? '';
  const all = ['Redmi Note 14', 'Realme Narzo 70', 'iPhone 16', 'Redmi 13C'];
  const hits = all.filter((n) => n.toLowerCase().includes(q.toLowerCase()));
  return Response.json({ q, count: hits.length, hits });
}

async function main() {
  const res = await GET(new Request('http://localhost:3000/api/search?q=redmi'));
  console.log(res.status, res.headers.get('content-type'));
  console.log(await res.json());
}
main();

Output

200 application/json
{ q: 'redmi', count: 2, hits: [ 'Redmi Note 14', 'Redmi 13C' ] }