Introduction
Next.js Server Actions let you run server-side code directly from your React components, without needing API routes. This feature makes form submissions faster, more secure, and easier to manage. Instead of sending data to an API endpoint, you can call a server function directly from a form. In this article, we will learn how Server Actions work and how to use them for real-world form submissions in a practical and straightforward way.
What Are Server Actions in Next.js?
Server Actions are special server-side functions that run securely on the server. They allow you to handle tasks like saving form data, inserting records into a database, sending emails, and validating user inputs—all without creating separate API routes.
Server Actions:
Run only on the server.
Cannot be accessed publicly from the browser.
Improve security by hiding business logic.
Reduce code complexity by removing unnecessary API routes.
Example structure:
'use server';
export async function submitForm(data) {
console.log('Form received:', data);
}
How to Create a Server Action
To create a Server Action, define a function inside a component or in a separate file and start it with:
'use server';
This tells Next.js to treat the function as a server-only function.
Example:
// app/actions/formActions.js
'use server';
export async function saveUser(formData) {
const name = formData.get('name');
const email = formData.get('email');
console.log('Saving user:', name, email);
}
How to Use Server Actions in a Form
Using a Server Action in a form is extremely simple. Instead of submitting to an API route, you assign the Server Action directly to the form's action attribute.
Example:
// app/register/page.jsx
import { saveUser } from '../actions/formActions';
export default function RegisterPage() {
return (
<form action={saveUser} className="space-y-4">
<input type="text" name="name" placeholder="Enter name" required />
<input type="email" name="email" placeholder="Enter email" required />
<button type="submit">Submit</button>
</form>
);
}
Now, when the user submits the form, it calls the Server Action directly.
How Server Actions Handle Form Data
The Server Action automatically receives the form data as FormData.
Example:
'use server';
export async function saveUser(formData) {
const name = formData.get('name');
const email = formData.get('email');
// Save to database
await db.user.create({ data: { name, email } });
return "User saved successfully";
}
This approach is secure because the database code runs only on the server.
Handling Validation in Server Actions
You can add validation directly in the Server Action.
'use server';
export async function saveUser(formData) {
const email = formData.get('email');
if (!email.includes('@')) {
throw new Error('Invalid email address');
}
// Continue saving
}
If validation fails, Next.js returns the error to your component.
Returning Data from Server Actions
A server action can return values like messages, objects, or redirect instructions.
Example: Return success message
return { success: true, message: "User added" };
Example: Redirect after form submit
import { redirect } from 'next/navigation';
export async function saveUser(formData) {
// Save user
redirect('/success');
}
Using Server Actions with Async UI Updates
Server Actions work perfectly with React's useTransition to show loading states.
Example:
'use client';
import { useTransition } from 'react';
import { saveUser } from '../actions/formActions';
export default function RegisterForm() {
const [isPending, startTransition] = useTransition();
return (
<form
action={(formData) => {
startTransition(() => saveUser(formData));
}}
>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button>
</form>
);
}
When Should You Use Server Actions?
Server Actions are perfect for:
Submitting forms
Contact forms
Login & registration
Feedback systems
Database inserts and updates
Sending emails
File uploads
Avoid using them for heavy background tasks; use Background Jobs or API routes instead.
Best Practices
Keep actions in a separate file
Helps maintain cleaner code.
Use Zod or custom validation
Ensures only valid data reaches the server.
Avoid console logs in production
Use proper logging tools.
Keep Server Actions lightweight
They should handle logic quickly and return results fast.
Join the conversation! Your thoughts help the community grow.