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

Client → API → Server → Database → Response

With Server Actions

With Server Actions, the flow is simplified:

Client Form → Server Action → Database

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.

FeatureServer ActionsAPI Routes
PurposeMutationsPublic APIs
Client fetch neededNoYes
SecurityVery high High
PerformanceFasterSlightly slower