CPCODELAB
Next.js

Server Actions and Mutations

11 min read

Mutating Data Without an API Route

Server Actions are async functions marked with "use server" that run exclusively on the server but can be called directly from Client Components or form action props. They eliminate the need for a separate API route for most mutations.

ts
// src/lib/actions.ts
"use server";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";

export async function createPost(formData: FormData) {
  const title = formData.get("title") as string;
  const body = formData.get("body") as string;

  if (!title || !body) throw new Error("Title and body are required");

  await db.post.create({ data: { title, body } });
  revalidatePath("/blog");
}
tsx
// src/app/blog/new/page.tsx
import { createPost } from "@/lib/actions";

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Title" required />
      <textarea name="body" placeholder="Content" required />
      <button type="submit">Publish</button>
    </form>
  );
}

You can also call Server Actions from Client Components using useTransition or the useActionState hook for pending and error states.

Server Actions are the recommended way to handle form submissions and mutations in the App Router. They work with progressive enhancement — the form submits even if JavaScript is disabled in the browser.

Ready to test yourself?
Practice Next.js— quiz & coding exercises