Route Handlers in Next.js: `route.js` Explained

How route.js files turn folders in the App Router into API endpoints, which HTTP methods they support, and how the file path becomes the URL.

6 min read

Route handlers are how Next.js exposes plain HTTP endpoints in the App Router. A route.ts file inside the app directory exports functions named after HTTP methods, and the framework turns that file into a URL that any client can call.

Where a page renders UI, a route handler returns a raw response such as JSON, text, or a redirect. Here is the smallest handler, which answers GET requests on /api/health and returns JSON.

typescripttypescript
// app/api/health/route.ts
export async function GET() {
  return Response.json({ status: 'ok' })
}

Visiting /api/health returns a JSON object with status ok. The function name GET is the HTTP method, and the folder path app/api/health becomes the URL.

Where the file must live

The route file has to sit inside the app directory, and its folder path is the endpoint path. A file at app/api/posts/route.ts answers requests on /api/posts, while app/dashboard/settings/route.ts answers /dashboard/settings.

The file name is always route.js or route.ts. Next.js treats the file as a route convention, not as UI, so it never renders. If a route.ts and a page.tsx exist in the same folder, Next.js reports a route conflict, so keep one endpoint type per folder.

HTTP methods are exported functions

Each HTTP method you want to support is a named export. Add one function per method, and each function receives the incoming request as its first argument.

typescripttypescript
// app/api/posts/route.ts
export async function GET(request: Request) {
  return Response.json({ posts: [] })
}
 
export async function POST(request: Request) {
  const body = await request.json()
  return Response.json({ created: true, ...body })
}

A GET request to /api/posts runs the GET export, and a POST request runs the POST export. A method without a matching export returns 405 Method Not Allowed.

Next.js supports GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. When you do not define OPTIONS, Next.js generates it and sets the Allow header from the methods you exported.

MethodTypical use in a handler
GETRead a resource or list
POSTCreate a resource or accept a webhook
PUT and PATCHUpdate a resource
DELETERemove a resource

PUT and PATCH are both update methods, but the difference is your API contract, not Next.js. The router only sends the method to its matching function.

Reading the request and route params

The first argument is a Request, or a NextRequest when you import the type from next/server. NextRequest adds cookie helpers and a parsed nextUrl object with searchParams. See NextRequest and NextResponse for those helpers.

Dynamic route segments arrive through a context object whose params field is a Promise, so it must be awaited.

typescripttypescript
// app/posts/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params
  return Response.json({ id })
}

A request to /posts/42 returns a JSON object with id 42. Route params became asynchronous in Next.js 15, and Next.js 16 fully removed synchronous access, so await the Promise before reading id. See handling GET, POST, PUT, PATCH, and DELETE for the full method map.

When to use a route handler

Use a route handler when a client outside your app needs a stable URL, such as a webhook receiver or a public API. For example, a payment provider calls back at /api/webhooks/payments, which you implement as a route handler because the provider needs a URL outside your app.

If the caller is your own form or button, a Server Action is usually simpler because it has no URL to manage. See Server Actions vs API Routes vs Route Handlers to choose between them.

Common mistakes

The first mistake is exporting a lowercase function name such as get. Method names are case sensitive, and Next.js only recognizes the uppercase names, so a lowercase export is ignored.

The second is assuming the file name shows up in the URL. A file at app/api/route.ts serves /api, not /api/route, because the folder path is the endpoint and the file name is just the convention.

Also note that layouts and pages in the same folder do not wrap a route handler, because the handler returns a raw response instead of rendering.

Rune AI

Rune AI

Key Insights

  • A route.js file exports functions named after HTTP methods like GET and POST.
  • The file path under app becomes the endpoint URL.
  • Each handler receives a Request and an optional context with awaited params.
  • Next.js auto-generates OPTIONS when you do not define it.
  • Route Handlers use the Web Request and Response APIs, not the Pages Router pair.
RunePowered by Rune AI

Frequently Asked Questions

Do Route Handlers replace pages?

No. A route file and a page file answer different request types at the same path. Route Handlers answer API-style requests with a raw response, while pages render UI. They can share an app, but they cannot live in the same folder.

Which HTTP methods can a route handler export?

A route handler can export GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. If you do not define OPTIONS, Next.js generates it automatically and sets the Allow header from the methods you did export.

Are route handlers the same as API Routes?

No. API Routes are the older Pages Router convention that lives in pages/api. Route Handlers are their App Router replacement and use the Web Request and Response APIs instead of the NextApiRequest and NextApiResponse pair.

Conclusion

A route.js file is how the App Router exposes an API endpoint. Place it inside app, export functions named after HTTP methods, and return a Web Response. The folder path becomes the URL, while the request and route context provide the incoming data.