Next.js API routes vs route handlers is one of those migrations that looks trivial in the docs but bites you on caching semantics and runtime defaults. Both surface HTTP endpoints inside a Next.js project, but they sit in fundamentally different mental models — one is a Node.js request/response wrapper, the other is built on the Web Fetch API and plays by App Router rules.
What each one actually is
Pages Router API routes live at pages/api/**/*.ts. They receive a NextApiRequest (a thin wrapper over Node's IncomingMessage) and a NextApiResponse. The runtime is always Node.js. They are never statically analysed for caching by the framework — every request hits your serverless function.
App Router route handlers live at app/**/route.ts. They receive a standard Request and return a standard Response. Because they are Web-standard, they can run on the Node.js runtime, the Edge runtime, or be statically evaluated at build time if the framework determines the response is constant.
Side-by-side feature table






