Next.js Server Actions
Updated on
In Next.js 16, Server Actions are one of the most important architectural features. Server Actions allow you to run server-side code directly from the client, enabling seamless data mutations without traditional API routes.
They eliminate the need for separate API routes by allowing server-side code to be executed directly from the client.
Traditionally, when users submit data, the flow looked like this:
Without Server Actions
With Server Actions
With Server Actions, the flow is simplified:
No separate API route is required for internal operations.
This makes applications:
- More secure
- Faster
- Cleaner to maintain
What are Server Actions
Server Actions are async functions that run on the server but can be triggered directly from the UI.
They are mainly used for:
- Form submissions
- Database mutations
- Updating data
- Handling user interactions
use server directive
async function saveUser(formData: FormData) {
"use server"
const name = formData.get("name")
console.log(name)
}
This function runs on the server even though it is connected to a client-side form.
Basic Server Action form
Here is a simple example of a Server Action form:
export default function ContactPage() {
async function submitForm(formData: FormData) {
"use server"
const name = formData.get("name")
const email = formData.get("email")
console.log(name, email)
}
return (
<form action={submitForm}>
<input name="name" placeholder="Name" />
<input name="email" placeholder="Email" />
<button type="submit">Submit</button>
</form>
)
}
When the user submits the form:
- The form sends data to the server.
- The Server Action runs.
- The server processes the request.
- No fetch() call is needed.
Server Actions for Database Operations
Server Actions are ideal for handling database operations. You can perform CRUD operations directly within a Server Action without needing an API route.
async function createUser(formData: FormData) {
"use server"
const name = formData.get("name")
await db.user.create({
data: {
name: String(name)
}
})
}
Because the code runs on the server, database credentials remain secure.
Redirection After Submission
After a successful form submission, you might want to redirect the user to a different page. You can achieve this by using the `redirect` function from `next/navigation`.
import { redirect } from "next/navigation"
async function submit(formData: FormData) {
"use server"
const name = formData.get("name")
console.log(name)
redirect("/thank-you")
}
The redirect happens directly from the server.
Passing Server Actions to Client Components
Sometimes a form is inside a Client Component. You can pass Server Actions as props.
import Form from "./Form"
export default function Page() {
async function save(formData: FormData) {
"use server"
console.log(formData.get("name"))
}
return <Form action={save} />
}
Client Component
"use client"
export default function Form({ action }) {
return (
<form action={action}>
<input name="name" />
<button type="submit">Save</button>
</form>
)
}
Handling Form States
You can manage server validation using useFormState.
"use client"
import { useFormState } from "react-dom"
export default function Form({ action }) {
const [state, formAction] = useFormState(action, null)
return (
<form action={formAction}>
<input name="email" />
{state?.error && <p>{state.error}</p>}
<button type="submit">Submit</button>
</form>
)
}
Server Actions Vs API Routes
Server Actions and API Routes are both used to handle server-side logic in Next.js, but they have some key differences.
| Feature | Server Actions | API Routes |
|---|---|---|
| Purpose | Mutations | Public APIs |
| Client fetch needed | No | Yes |
| Security | Very high | High |
| Performance | Faster | Slightly slower |