"API Routes" is the name for backend endpoints in the Pages Router (pages/api), and it's a term still used broadly to describe any server endpoint built directly inside a Next.js app. This lesson covers the original pages/api convention and how it relates to the App Router's Route Handlers.
API Routes in the Pages Router
Any file inside pages/api/ automatically becomes a serverless API endpoint rather than a page. Instead of returning JSX, the default export is a handler function that receives Node.js-style req and res objects, similar to an Express route handler.
This was, for years, the standard way to add backend logic to a Next.js app — form submissions, webhook receivers, and simple CRUD endpoints — without needing a separate backend service.
// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ message: "Hello from the API!" });
}
This file automatically becomes reachable at /api/hello, with no additional routing configuration.
Handler Function Signature
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
// handle POST
}
res.status(200).json({ ok: true });
}
The handler receives Express-like req (request) and res (response) objects.
You branch on req.method manually to support multiple HTTP methods in one file.
res.status(code).json(data) sends a JSON response with the given status code.
Files under pages/api/ never render UI — they are purely backend endpoints.
API Routes (Pages Router) Cheat Sheet
Common request/response patterns for pages/api handlers.
Task
Code
Read query params
req.query.id
Read JSON body
req.body (auto-parsed for JSON)
Send JSON response
res.status(200).json(data)
Send an error
res.status(400).json({ error: "..." })
Check HTTP method
if (req.method === "POST")
Dynamic API Routes
Just like pages, API routes support dynamic segments using the same bracket syntax, with the captured value available on req.query.
// pages/api/posts/[id].ts
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query;
res.status(200).json({ postId: id });
}
API Routes vs. App Router Route Handlers
The App Router replaces this pattern with Route Handlers (route.ts files, covered in the next lesson), which use the standard Web Request/Response objects instead of Node.js-style req/res. Both accomplish the same goal — the API you use just depends on which router your project (or specific route) is using.
Aspect
API Routes (pages/api)
Route Handlers (app/.../route.ts)
Request/response style
Node.js-style req/res
Web-standard Request/Response
File location
pages/api/*.ts
app/**/route.ts
Method handling
Branch on req.method
Separate exported functions per method
Common Mistakes
Forgetting to check req.method, causing a GET-only handler to also (incorrectly) accept POST requests.
Returning data without calling res.status() explicitly, relying on an implicit default.
Mixing pages/api conventions into an App Router route.ts file (or vice versa) — the request/response APIs are different.
Not validating req.body, trusting client-sent data without any checks.
Key Takeaways
pages/api/*.ts files become serverless backend endpoints in the Pages Router.
Handlers use Node.js-style req/res objects, similar to Express.
Dynamic API routes use the same [param] bracket syntax as pages.
The App Router's equivalent concept is Route Handlers, using Web-standard Request/Response objects.
Both approaches let you build backend logic without a separate server.
Pro Tip
If you're starting a new project on the App Router, use Route Handlers instead of pages/api — but if you're maintaining an existing Pages Router codebase, there's no need to migrate working API routes just for the sake of it; both are fully supported.
You now understand API Routes. Next, learn Route Handlers — the App Router's modern equivalent for building backend endpoints.