Enhance Your Next.js Applications with Server Actions: A Step-by-Step Guide

As web applications grow more complex, managing server-side logic alongside client-side interactions can become a challenge.
The React 19 canary version released Server Actions, which will allow Client Components to call async functions that are executed on the server.
Fortunately, the latest version of Next.js App Router supports React Server Actions. With the introduction of Server Actions in Next.js App Router, developers now have a more streamlined way to handle server-side operations directly within their components. This not only simplifies your codebase but also improves performance by reducing the need for separate API routes.
In this post, we’ll explore how Server Actions can be used effectively in Next.js. To illustrate this, we’ll use an example from Bethany’s Pie Shop, a fictional bakery that needs to update a customer’s shopping cart in real-time as they add items like fresh pies and coffee.
What Are Server Actions?
Server Actions in Next.js allow you to run server-side logic directly within your React components. Instead of creating separate API routes, you can define these actions within your component files, making it easier to manage and maintain your code. Server Actions are particularly useful for handling data mutations, like updating a shopping cart, processing form submissions, or interacting with a database.
Example: Updating a Shopping Cart at Bethany’s Pie Shop
Let’s dive into a practical example. Bethany’s Pie Shop wants to update a user’s shopping cart dynamically when they add pies or coffee to their order. We’ll see how Server Actions can handle this smoothly.
Setting Up the Server Action
1. Server Action: actions.js
We’ll start by defining a server action that will handle adding items to the shopping cart. This action will run on the server and update the cart based on the user’s selection.
// Server Action: actions.js
'use server';
export async function addItemToCart(item) {
// Simulate a server-side cart update
const response = await fetch('/api/cart', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(item),
});
if (!response.ok) {
throw new Error('Failed to add item to cart.');
}
return response.json();
}
This action function is designed to be called from the client component and will handle the logic of adding an item to the shopping cart on the server side.
Integrating Server Actions in Components
2. Server Component: ShoppingCart.js
Next, we create a server component that renders the shopping cart interface and passes the server action to the client component.
// Server Component: ShoppingCart.js
import { addItemToCart } from './actions';
import ShoppingCartClient from './ShoppingCartClient';
export default function ShoppingCart({ items }) {
return (
<div>
<h2>Your Shopping Cart</h2>
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name} - ${item.price}
</li>
))}
</ul>
<ShoppingCartClient onAddItem={addItemToCart} />
</div>
);
}
This server component handles rendering the list of items in the cart and provides the ShoppingCartClient
component with the server action to use when items are added.
3. Client Component: ShoppingCartClient.js
The client component is where the user interacts with the cart by adding items. This component calls the server action when a user adds a pie or coffee to their cart.
'use client'; // Marks this as a Client Component
import { useState } from 'react';
export default function ShoppingCartClient({ onAddItem }) {
const [item, setItem] = useState('');
const [status, setStatus] = useState('');
async function handleAddToCart() {
try {
const itemData = { id: Date.now(), name: item, price: item === 'Pie' ? 10 : 5 };
await onAddItem(itemData);
setStatus(`${item} added to cart!`);
} catch (error) {
setStatus('Failed to add item to cart.');
}
}
return (
<div>
<select onChange={(e) => setItem(e.target.value)} value={item}>
<option value="">Select an item</option>
<option value="Pie">Pie</option>
<option value="Coffee">Coffee</option>
</select>
<button onClick={handleAddToCart}>Add to Cart</button>
{status && <p>{status}</p>}
</div>
);
}
This component enables users to add an item to their cart. The handleAddToCart
function is responsible for calling the server action and updating the UI based on the result.
Mocking the Server Logic
To simulate the server-side logic, we can create a mock API that handles the cart updates. This example uses a simple in-memory array to store cart items.
Create an API route in pages/api/cart.js
:
// pages/api/cart.js
let cart = [];
export default function handler(req, res) {
if (req.method === 'POST') {
const item = req.body;
cart.push(item);
res.status(200).json({ message: 'Item added to cart', cart });
} else {
res.status(405).json({ message: 'Method not allowed' });
}
}
This API route handles the cart updates by adding items to the in-memory cart array. In a production environment, you would replace this with database logic.
Bringing It All Together
When users interact with the cart, the client component sends their selection to the server action, which updates the cart on the server. The UI updates in real-time, providing a smooth and responsive user experience.
Why Use Server Actions?
Server Actions in Next.js offer several advantages:
- Simplified Codebase: By handling server-side logic directly in your components, you reduce the need for separate API routes, making your application easier to maintain.
- Enhanced Performance: Server Actions run on the server, ensuring that sensitive operations are performed securely and efficiently.
- Improved Developer Experience: With Server Actions, you can keep related logic together, leading to cleaner and more organized code.
Conclusion
Server Actions are a game-changer for developers building full-stack applications. They offer a straightforward way to handle server-side logic within your components, making it easier to manage and scale your application. Whether you’re updating a shopping cart at Bethany’s Pie Shop or handling complex data operations, Server Actions can help you build more efficient and maintainable applications.
Ready to start using Server Actions in your projects? Dive in and see how they can streamline your development workflow!
Resources and Connect with me
Alright folks, that’s a wrap! Hope you enjoyed this article! Here are some resources that will come handy in your journey to learn React and Next.js:
You can check out my latest course on Next.js 14: Foundations on Pluralsight below:
https://www.pluralsight.com/library/courses/nextjs-13-fundamentals/table-of-contents
For information on my consulting services visit: adhithiravichandran.com
To stay connected follow me @AdhithiRavi or linkedIn/adhithi