Server Actions vs API Routes in Next.js 13: Unraveling the Power of Server-Side Logic
The use of Server Actions or API Routes has been an ongoing debate for the past few months since the release of Next.js 13.
Luckily for you, I am here today to break the ice, and give a definitive guide on Server Actions, as well as touch on API routes in Next.js 13 with implementation examples for both.
I have taken a long break from blog writing as I am adapting to university life, so apologies in advance if you find my writing style sub-par.
Anyways, without further ado, lets get into it!
Table of Contents
- Setup Next.js 13 Project Environment
- Server Actions
- API Routes
Setup Next.js 13 Project Environment
To setup a Next.js project, please check out the instructions here. The installation process generally consists of running the following command in the terminal.
npx create-next-app@latest
Next you should enable server actions, We will be creating a server action later, and this is required to enable them in Next.js 13.
To do this, go into your next.config.js
file and copy the following:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
}
module.exports = nextConfig
Server Actions
Server actions have been out for a while now in the realm of Next.js 13, yet they still amaze me; the ability to perform server-side mutations directly from client-side code with minimal code should not be overlooked.
Here is an example of a server action in Next.js 13:
'use server'
export async function myAction() {
// ...
}
It’s good practice to create a folder called _actions
inside the app/
directory which will contain each of your server actions.
Now to run the server action from a client-side context:
'use client'
import { myAction } from './actions'
export default function ClientComponent() {
return (
<form action={myAction}>
<button type="submit">Add to Cart</button>
</form>
)
}
Now whenever the button “Add to Cart” is pressed, Next.js 13 will generate an API route under the hood with the correct HTTP method like it’s magic.
Another new feature regarding server actions is the ability to bind
arguments to a server action via the new bind()
method; here is an example illustrating this feature:
'use client'
import { updateUser } from './actions'
export function UserProfile({ userId }) {
const updateUserWithId = updateUser.bind(null, userId)
return (
<form action={updateUserWithId}>
<input type="text" name="name" />
<button type="submit">Update User Name</button>
</form>
)
}
The use of the bind
here assigns userId
as an argument to the updateUserWithId
server action; this feature acts like a method overloading mechanism, which provides flexibility and customizability for your server actions after they’ve been defined.
You can also think of the bind method as changing the method signature from this:
'use server'
export async function updateUser(formData) {
// ...
}
To this:
'use server'
export async function updateUser(userId, formData) {
// ...
}
API Routes
API Routes in Next.js 13 are very simple, the body of an API route definition is as follows:
export async function GET(request: Request) {}
- You name the function as the HTTP method you would like to use, in this case
GET
- You can pass in a
request
argument which contains the headers and body of your HTTP request. - NOTE: there cannot be a page and a route in the same folder.
By convention you would define route files as follows: app/api/route.ts
where route.ts represents the /api/
relative route.
Here is how you would access the /api
route in a client side component:
"use client"
const Component = () => {
useEffect(() => {
async function fetchData() {
const res = await fetch("/api", { method: "GET" })
return await res.json()
}
fetchData()
}, [])
}
NOTE: This works only in client components, in server components you would need to specify an absolute URL, e.g. localhost:3000/api
.
Conclusion
Overall, server actions remove the layer between the client and server side and allows for a seamless integration and data fetching experience. On the other hand, API routes are more stable and formally defined, giving you more control over HTTP methods and customizing headers.
If you enjoyed this article, check out my profile for many more stories like this, and stay tuned for future articles! 👍