Handling GET, POST, PUT, PATCH, and DELETE in a Route Handler

How each HTTP method maps to a named export in a Next.js route handler, and what to return for reads, creates, updates, and deletes.

6 min read

A route handler supports one HTTP method per exported function. You name an async export after the method, such as GET or POST, and Next.js calls that function when a request of that method arrives at the route.

Most APIs map the five core methods onto read, create, update, and delete operations. Here is a small handler with GET and POST.

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 })
}

GET returns the list, and POST returns a create-style result from the JSON body. A real POST handler would validate the input and write it through a data layer before returning. Each method is a separate export, and only the matching export runs for a given request.

The export name is the method

The method name is the function name, and it is case sensitive. Export GET to answer GET, POST to answer POST, and so on. If a client sends a method you did not export, Next.js responds 405 Method Not Allowed.

Next.js also handles OPTIONS and HEAD for you when you do not define them. The generated OPTIONS response sets the Allow header from the methods you exported. See Route Handlers in Next.js for the file convention and placement.

Update with PUT and PATCH

PUT and PATCH both update a resource, but they signal different intents. PUT replaces the whole resource, while PATCH applies a partial change. Next.js does not enforce the difference, so the meaning lives in your code.

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

A PUT request to /api/posts/42 makes this sample return the id and submitted fields. In a real handler, the data layer would replace post 42 before that response is returned.

The params object is a Promise, so you await it before reading the id.

A PATCH handler has the same shape but reads only the fields the client wants to change and merges them into the existing resource. Whether you treat PATCH as a partial update is your API contract, not something Next.js checks.

Remove with DELETE

DELETE removes the resource identified by the route. A successful delete usually returns 204 No Content, which means the response has no body.

typescripttypescript
// app/api/posts/[id]/route.ts
export async function DELETE(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params
  return new Response(null, { status: 204 })
}

Calling DELETE on /api/posts/42 makes this sample return an empty 204 response. A real handler must delete the row in its data layer before returning that response.

Choose the right status code

The status code is part of your response, not the method. Return 200 for a successful read, 201 when POST creates a resource, and 204 for a delete with no body. Use 400 or 422 when the input is invalid, and 404 when the route param points at nothing.

Being explicit beats returning 200 for everything, because clients branch on the status code. Response.json and new Response both accept a status in their options argument, so set it where you build the response.

For the post/redirect/get pattern, return 303 with a Location header. The Next.js redirect helper returns 307 in a Route Handler, which preserves the original request method instead of changing POST to GET.

Return the right response

What you return is up to each method. Return JSON with data for reads, a 201 status for creates, and a 204 or the updated resource for updates and deletes.

The return value is what the client receives, so match its shape to what the client expects. See returning JSON, files, streams, and redirects for the response shapes.

To read the incoming body, query params, or headers before deciding what to do, see reading the request body, query params, and headers.

Common mistakes

A lowercase function name such as get is ignored, because method names are case sensitive and Next.js only recognizes the uppercase form. The export must be named exactly GET, POST, PUT, PATCH, or DELETE.

Another common mistake is reading params without await, which returns a Promise instead of the value. Always await params inside the second argument before using its fields.

A third mistake is forgetting to return a response from every code path. Each method should return a Response, including in error branches, or the handler fails without producing a valid reply.

Rune AI

Rune AI

Key Insights

  • One named export answers one HTTP method, and names are case sensitive.
  • Missing exports return 405 Method Not Allowed automatically.
  • OPTIONS is generated for you when you do not define it.
  • PUT replaces a resource, while PATCH applies a partial update.
  • DELETE returns a response such as 204 with no body.
RunePowered by Rune AI

Frequently Asked Questions

What happens when a client calls a method I did not export?

Next.js returns 405 Method Not Allowed. You do not need to write that fallback response yourself.

Should PUT and PATCH behave differently?

By convention PUT replaces the whole resource and PATCH applies a partial update, but Next.js does not enforce the difference. The semantics live in your handler code and your API contract.

Do I need to handle OPTIONS myself?

No. If you do not export OPTIONS, Next.js generates it automatically and sets the Allow header from the methods you did export. You only write an OPTIONS export for a custom preflight response.

Conclusion

Each HTTP method in a route handler is a separate named export. Name functions after the uppercase method, return a Web Response, and let Next.js enforce 405 and OPTIONS for you. Keep GET side-effect free, use POST for creates, PUT and PATCH for updates, and DELETE for removal.