405 Method Not Allowed · Allow: GET
appears when:When a client calls a Next.js API route with an HTTP method that has no matching named export in route.ts (App Router) or no req.method branch (Pages Router)
API route returns 405 Method Not Allowed
Next.js App Router matches HTTP methods to named exports. If POST is not exported, POST returns 405. The fix is one new function — five minutes.
route.ts. Export async function GET / POST / PUT / PATCH / DELETE as needed. On Pages Router, branch on req.method. If output: "export" is set in your config, API routes are disabled entirely — remove that line.Quick fix for API route 405
01// app/api/tasks/route.ts — App Router: one named export per HTTP method02import { NextResponse } from "next/server";03 04export async function GET(req: Request) {05 const { searchParams } = new URL(req.url);06 const userId = searchParams.get("userId");07 return NextResponse.json({ tasks: [], userId });08}09 10export async function POST(req: Request) {11 const body = await req.json();12 // create task...13 return NextResponse.json({ ok: true, created: body }, { status: 201 });14}15 16export async function DELETE(req: Request) {17 const { searchParams } = new URL(req.url);18 const id = searchParams.get("id");19 // delete task...20 return new Response(null, { status: 204 });21}22 23// Any method not exported returns 405 automatically24// Supported methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONSDeeper fixes when the quick fix fails
01 · Pages Router — single handler with method branching
01// pages/api/tasks.ts — Pages Router explicit method branching02import type { NextApiRequest, NextApiResponse } from "next";03 04export default async function handler(req: NextApiRequest, res: NextApiResponse) {05 if (req.method === "GET") {06 return res.status(200).json({ tasks: [] });07 }08 if (req.method === "POST") {09 return res.status(201).json({ ok: true });10 }11 // explicit 405 for anything else — set Allow header so clients know what's supported12 res.setHeader("Allow", "GET, POST");13 return res.status(405).json({ error: "method_not_allowed" });14}02 · Contract test hits every method
01// tests/api/tasks.contract.test.ts — Vitest contract test02import { describe, test, expect } from "vitest";03 04const BASE = process.env.TEST_BASE_URL ?? "http://localhost:3000";05 06describe("/api/tasks contract", () => {07 test("GET returns 200", async () => {08 const res = await fetch(`${BASE}/api/tasks`);09 expect(res.status).toBe(200);10 });11 12 test("POST returns 201", async () => {13 const res = await fetch(`${BASE}/api/tasks`, {14 method: "POST",15 headers: { "content-type": "application/json" },16 body: JSON.stringify({ title: "test" }),17 });18 expect(res.status).toBe(201);19 });20 21 test("PATCH returns 405 with Allow header", async () => {22 const res = await fetch(`${BASE}/api/tasks`, { method: "PATCH" });23 expect(res.status).toBe(405);24 expect(res.headers.get("allow")).toContain("GET");25 });26});03 · Typed route helper that enforces method coverage
01// lib/route.ts — helper that makes missing methods impossible to ship02type Handler = (req: Request) => Promise<Response>;03type Methods = { GET?: Handler; POST?: Handler; PUT?: Handler; DELETE?: Handler };04 05export function makeRoute(methods: Methods) {06 return methods;07}08 09// app/api/tasks/route.ts10import { makeRoute } from "@/lib/route";11 12export const { GET, POST } = makeRoute({13 GET: async () => Response.json({ tasks: [] }),14 POST: async (req) => {15 const body = await req.json();16 return Response.json({ ok: true, body }, { status: 201 });17 },18});Why AI-built apps hit API route 405
Next.js App Router introduced a new convention for API routes. Instead of a single default handler (as in Pages Router), each HTTP method is a named export: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. When a request arrives, Next.js looks up the method in the module exports. If no match exists, the framework returns a 405 with an Allow header listing the methods that do exist. There is no fallthrough to a default handler. There is no way to catch-all from inside the route file.
AI builders trained on Pages Router examples often write export default async function handler(req, res) inside app/api/tasks/route.ts. The default export is simply ignored. No warning is printed at build time. The first POST /api/tasks returns 405. The same code pasted into pages/api/tasks.ts would work perfectly — but router mixing silently fails.
The second common source is a partial fix. An AI tool adds POST to the route.ts file but the client is sending PUT. The fix is always to match the client's verb to the server's export, and ideally document the supported methods in the route handler so both sides agree.
The third source is build configuration. Setting output: "export" in next.config.ts tells Next.js to generate a fully static site. API routes are not static — they need a server. In static export mode the framework fails at build with a warning, or ships the static HTML and the API path returns 405 (or 404) at runtime. Remove the output line if you need dynamic routes. Finally, middleware that rewrites or returns a response can intercept the request; confirm your matcher does not cover the API path unexpectedly.
API route 405 by AI builder
How often each AI builder ships this error and the pattern that produces it.
| Builder | Frequency | Pattern |
|---|---|---|
| Lovable | Every App Router scaffold | Writes export default handler in route.ts — silently ignored |
| Bolt.new | Common | Mixes Pages Router imports inside an App Router project |
| v0 | Common | Exports only GET when client also needs POST |
| Cursor | Sometimes | Leaves output: 'export' in next.config after scaffolding a static demo |
| Replit Agent | Rare | Middleware rewrites /api/* to a path that only exports GET |
Related errors we fix
Stop API route 405 recurring in AI-built apps
- →Use named method exports in App Router — never export default from route.ts.
- →Write a contract test that asserts each API returns expected statuses for every method.
- →Never set output: 'export' in a project that ships API routes.
- →Grep the repo for `export default.*route.ts` and ban it in code review.
- →Use a typed makeRoute helper so missing methods fail at compile time.
Still stuck with API route 405?
API route 405 questions
Why does my Next.js API route return 405 Method Not Allowed?+
What is the difference between App Router and Pages Router API handlers?+
Why did my API route start returning 405 after enabling static export?+
Can middleware cause a 405 on my API route?+
How long does an API 405 fix take?+
Ship the fix. Keep the fix.
Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.
Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.