Server Actions vs Route Handlers in Next.js

Next.js allows you to use Server Actions or API Route Handlers to execute code server side and call it from the client. Which one should you use?

There are two ways to execute server-side code in Next.js:

  1. Server Actions
  2. 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:

  1. 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.
  2. 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:

app/lib/server-actions.ts
'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:

app/page.tsx
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:

app/api/hello/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:

  1. 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.
  2. 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.
  3. 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?

  1. 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.
  2. 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.