API Routes, Route Handlers, Server Components and Server Actions in Next.js: all the differences
Breaking down the key differences between all these terms, plus a couple extra clarifications about Next's own Request and Response.
After reading through a variety of libraries and component documentation for React and Next.js, I noticed that even the authors often confuse the differences between API Routes, Route Handlers, Server Components and Server Actions in Next.js.
After watching this Youtube video by Lee Robinson, VP of Product at Vercel, who addresses some of the common mistakes with Next.js, I though’t I’d I’d write my own blog post to explain things in the "Silvestri" way!
As usual, if you find this article helpful, feel free to give me a shoutout on X/Twitter, I’d really appreciate it.
Let’s get started!
TL;DR
- API Routes: use to expose a public API in Next.js Pages Router.
- Route Handlers: use to expose a public API in Next.js App Router.
- Server Components: use to render UI server side in Next.js App Router.
- Server Actions: use to fetch data or handle form submissions in Next.js App Router.
API Routes
API Routes are part of Next.js Pages Router and should only be used if you want to build a public API - an endpoint you want external developers or applications to reach.
To create an API route, place a file under the pages/api
folder. The following is an example directly from the documentation:
// pages/api/hello.ts import type { NextApiRequest, NextApiResponse } from 'next' type ResponseData = { message: string } export default function handler( req: NextApiRequest, res: NextApiResponse<ResponseData> ) { res.status(200).json({ message: 'Hello from Next.js!' }) }
As you can see, the stars of this code are NextApiRequest and NextApiResponse. This is where I find Next.js’ documentation quite unclear, given that NextRequest and NextResponse also exist, and there are plenty of related questions on both Stackoverflow and Reddit.
Let me give you a clarification on this:
- NextApiRequest and NextApiResponse are part of the global “next” package and help you make the API Route type-safe. They also extend ServerResponse directly from Node.js by providing additional helper methods, known as Request Helpers and Response Helpers respectively. These were the way to go when only the Pages Router was available.
- NextRequest and NextResponse are part of the “next/server” package and the main difference is that they directly extend the Response API. They are available on both Pages (API Routes) and App (Route Handlers) routers, and do more or less the same job but in a different way.
Long story short: if you are using the API Routes (Pages Router), you’ll use NextApiRequest and NextApiResponse; if you are using the Route Handlers (App Router - see below) you’ll use NextRequest and NextResponse.
Yes, I know — it’s a lot of “routes“ and “routers“ to digest!
Route Handlers
Route Handlers are available in the App Router and replace API Routes altogether. Again, you may want to use these if you need to provide a public API. They are defined as a route.js
or route.ts
file within the app
directory, and you can’t have them in the same folder of a page.js
or page.ts
file.
The key difference here is that instead of using a handler
function function, you define the HTTP methods directly: GET
, POST
, PUT
, PATCH
, DELETE
, HEAD
, and OPTIONS
.
For example:
// app/api/route.ts import { cookies } from 'next/headers' export async function GET(request: Request) { const cookieStore = await cookies() const token = cookieStore.get('token') return new Response('Hello, Next.js!', { status: 200, headers: { 'Set-Cookie': `token=${token.value}` }, }) }
Server Components
Server Components are another addition, introduced along with Route Handlers, in the Next.js App Router. They come directly from React. By default, every component in Next.js is a Server Component, unless you add the 'use client'
directive at the top of the file.
Server Components, as the name implies, allow you to do stuff directly on the server, particularly render UI, and come with a lot of different benefits. For example, if you need to fetch data, you do so with Server Actions; and because both the UI rendering and the actions occur on the server, that's how you can gain significant performance improvements.
Next.js documentation doesn’t offer many specific examples of Server Components because they behave like any other component. The only restriction is that user interactions must happen on the client side.
You can, of course, have Client Components as child of a Server Component.
Server Actions
Server Actions, usually declared in dedicated action.ts
files, are asynchronous functions that are used to fetch data or handle form submissions.
While it's usually more convenient to call them from Server Components (keeping everything server-side), they can also be called from Client Components when user interaction is required.
To ensure all functions in a file are server actions, you need to explicitly set the ’use server’
directive at the top of it, plus all the functions must be declared as async
.
Alternatively, you can choose to only have a specific function declared as a server action. In such cases, you put the use server
directly inside of it, as shown here:
async function addToCart(data) { 'use server'; // Rest of the function here }
This approach allows you to use Server Actions within Server Components. However, the only way to include Server Actions in Client Components is to import them from the above mentioned, separate action.ts
file.
Conclusions
I hope this article has clarified the often confusing terminology surrounding React and Next.js. I’d be more happy to hear your feedback about this article, so feel free to get in touch anytime.