Next.js has long been known as the go-to framework for React frontends. But with the latest releases, it has also grown into a capable backend framework. Developers no longer need to pair Next.js with Express or another Node.js server to build APIs. Instead, you can use the built-in routing system to create scalable, production-ready APIs right inside your Next.js app.
Let’s walk through why this shift matters and how you can start building APIs with nothing but Next.js.
Why Skip Express?
Express is lightweight and flexible, but it adds another dependency to maintain. You have to wire up routes, middleware, and deployment settings separately. Next.js removes that extra layer by handling both your frontend and backend in one place.
That means,
One deployment pipeline instead of two.
Serverless-friendly by default when hosting on Vercel or AWS Lambda.
Built-in support for modern tooling like TypeScript, Edge Runtime, and middleware.
If your use case is a typical full-stack application, running API routes directly inside Next.js often makes more sense than spinning up an entire Express app.
API Routes with Next.js
Next.js started supporting API routes back in the pages/api folder. Today, the App Router introduces Route Handlers, which give you even more flexibility. You can export functions that match HTTP verbs ( GET, POST, PUT, etc.) inside your route files.
Here’s a simple example using the App Router ( app/api/hello/route.ts ).
// app/api/hello/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({ message: "Hello from Next.js API!" });
}
export async function POST(req: Request) {
const data = await req.json();
return NextResponse.json({ received: data });
}
With just this file, you have a REST endpoint /api/hello that handles both GET and POST: no Express setup, no routing boilerplate.
Building a Scalable API
Let’s say you are building a to-do application. A basic CRUD API in Next.js could look like this.
// app/api/todos/route.ts
import { NextResponse } from "next/server";
let todos: { id: number; task: string }[] = [];
// GET all todos
export async function GET() {
return NextResponse.json(todos);
}
// POST a new todo
export async function POST(req: Request) {
const { task } = await req.json();
const newTodo = { id: Date.now(), task };
todos.push(newTodo);
return NextResponse.json(newTodo, { status: 201 });
}
That’s enough to serve data to your React frontend without ever touching Express. For persistence, you can connect this to databases like PostgreSQL, MongoDB, or even use Prisma ORM for a clean developer experience.
Middleware for Control
What about middleware like authentication or logging? Next.js ships with a middleware.ts file that runs before every request.
Example: simple auth check for protected routes.
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(req: NextRequest) {
const token = req.cookies.get("token");
if (!token && req.nextUrl.pathname.startsWith("/api/secure")) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
return NextResponse.next();
}
This gives you control over API requests without relying on Express middleware chains.
Deployment at Scale
One of the biggest wins with Next.js APIs is how they deploy. Hosting providers like Vercel, Netlify, and AWS convert your route handlers into serverless functions automatically. That means your API scales up under load and scales down to zero when idle.
For example
A burst of traffic will spin up multiple function instances.
No servers to manage or autoscaling groups to configure.
You only pay for execution time.
In traditional Express apps, you would have to configure load balancers and worry about scaling manually.
Performance and Edge
Next.js also supports the Edge Runtime, powered by V8 isolates instead of Node.js processes. APIs running on the edge respond faster to users worldwide. You can enable this by exporting a config.
export const runtime = "edge";
That small change deploys your API routes to edge locations, reducing latency for global traffic.
When You Might Still Want Express?
There are still cases where Express might be better.
If you already have an existing Express app and want to keep it.
If your API is extensive and independent of any frontend.
If you need custom middlewares or patterns that Next.js does not yet support.
But for most new projects where frontend and backend live together, Next.js provides enough API capability without extra overhead.
Wrapping Up
Next.js is no longer just a frontend framework. It has matured into a platform where developers can build both UI and APIs under one roof. By skipping Express, you reduce dependencies, simplify deployments, and unlock built-in serverless and edge capabilities.
For developers building modern full-stack apps, learning how to write APIs directly in Next.js is not just convenient. It is a more innovative, more scalable way to ship code.