There are two ways to execute server-side code in Next.js:
- Server Actions
- API Route Handlers
It's often misunderstood which ones to use. This article will help you understand the differences between them.
Server Actions Functions
Server Actions, introduced in Next.js 13, are special functions that, while they are executed server side, can be called from React Components client-side just like any other Javascript function.
There are two ways to define a Server Action:
- Globally per file: Using the directive
use server
at the top of the file. This turns every exported function in the file into a Server Action. - Per Function: Using the
use server
directive at the top of the body of a function. This turns the function only into a Server Action.
To declare all the exported functions as server actions, we place the directive use server
at the top of the file:
'use server';export async function createPostAction(data: { title: string; content: string;}) { const db = createDbService(); const result = await db.createPost(data); return { success: true };}
Instead, we can also declare a Server Action in a Server Component:
function MyComponent() { // form that uses "createPostAction"}async function createPostAction(data: { title: string; content: string;}) { 'use server'; const db = createDbService(); const result = await db.createPost(data); return { success: true };}
Normally, it's more common to create a server actions file, because it's more common to call Server Actions from Client Components (in my experience).
It's very important to note that Server Actions, at this time, are exclusively POST requests. POST requests are suitable for creating, updating, and deleting data, but they're not suitable for reading data.
Server Functions
Starting from Next.js 15/React 19, Server Actions are no longer a thing, or better said, they're a type of Server Function. Server Functions, like Server Actions, are functions that can be called from the client-side.
However, unlike Server Actions which are POST-only, Server Functions can be called using any HTTP method.
At this time, they're still experimental, however it's where React is heading. For more information, please head to the Server Functions documentation.
Route Handlers
Route Handlers are "normal" API routes that we would commonly use in Next.js Pages Router, or similar frameworks.
Next.js allows us to create API handlers by exporting a function named like an HTTP verb from special files named route.ts
:
import { NextRequest, NextResponse } from 'next/server';export const GET = async (request: NextRequest) => { const db = createDbService(); const posts = await db.getPosts(); return NextResponse.json(posts);};
The GET
function exported from a route.ts
file will turn the function into an API handler responding to GET
requests.
Since we created the file at app/api/hello/route.ts
, Next.js will automatically create a route at /api/hello
that will respond to GET
requests and execute the body of the function as a server-side function.
If you were to export a function named POST
from the same file, Next.js would create a route at /api/hello
that would respond to POST
requests and execute the body of the function as a server-side function.
Main Differences between a Server Action and a Route Handler in Next.js
As you can see, there are similarities between a Server Action and a Route Handler, but there are also some key differences:
- Server Actions are exclusively POST requests: Server Actions are exclusively executed on the server, and they're only executed when a POST request is made. This means that Server Actions are not suitable for reading data. This is true at this time, but with Server Functions being released, things are likely going to change.
- Server Actions are not suitable for reading data: At this time, refrain from using a Server Action instead of a GET request to read data. GET requests are preferable for reading data since you can cache them natively.
- Server Actions are only usable from your Next.js app: Server Actions are only usable from your Next.js app, and are not meant to be used externally.
When should you use a Server Action?
Prefer Server Actions for mutations when calling a mutation (POST, DELETE, UPDATE) from within your Next.js application.
The enhanced developer experience from Server Actions makes them perfect to call Server-side functions from within your Next.js application.
In fact, calling a Server Actions is just like any other function, except Next.js will automatically run it on the server.
<form onSubmit={e => { e.preventDefault(); // Call the Server Action return createPostAction(data);}> {/* ... */}</form>
You also get strong-typing for free, since you're just calling a function.
Instead, calling a Route Handler involves using a fetch
call to the API. Which it isn't hard, bit it's not as convenient as calling a Server Action.
When should you use a Route Handler?
- Prefer Route Handlers when fetching data from a Client Component: GET requests can be cached and are more suitable for reading data. This may change with the introduction of Server Functions, so keep an eye on this.
- Use Route Handlers when calling the API from an external source: whether you're using a GET, POST or any other HTTP method, Route Handlers are the way to go when calling the API from an external source (webhooks, APIs, etc.).
NB: in the future, Server Functions will allow us to call different HTTP methods, so Route Handlers will become less relevant in the context of calling these functions from within the Next.js application.
Conclusion
In this article, we've explored the different ways to call the API from within your Next.js application.
I hope this article has been useful to you, and I'd love to hear your thoughts on it.