Skip to the solution
HardFrontend6 min read

What are Server Actions in Next.js and how do they work?

842 views

The problem

Question presented to candidate: "Explain what happens, end to end, when a user clicks a button that calls a Server Action. What travels over the network, and what does the action return?"

What a strong answer should cover:

  • A Server Action (React Server Function) is an async function marked with 'use server'; it runs only on the server.
  • The client never gets the code: it gets a reference (an action id) and calls it with a POST to the current route, carrying the arguments.
  • The response is an RSC stream with the return value, and it can also carry a fresh render of the page when the action revalidates.
  • Actions can be passed to forms (action={fn}), called from event handlers, or used with useActionState.
  • Every action is a public HTTP endpoint: authenticate and authorise inside it; the client dispatches actions one at a time.

Clarifying questions expected:

  • "Is this a mutation or a read?" β€” actions are designed for mutations.
  • "Who is allowed to trigger it?" β€” the check belongs inside the action.

Code / implementation expected: Yes β€” an actions file, a form and a button calling it.

  • nextjs
  • server-actions
  • mutations
  • rsc

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 8 sections

Read the code

An actions file, a form and a client button
// app/posts/actions.ts
"use server";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { auth } from "@/lib/auth";

export async function createPost(formData: FormData) {
  const session = await auth();
  if (!session) throw new Error("Not signed in");
  const title = z.string().min(1).max(120).parse(formData.get("title"));
  await db.post.create({ data: { title, authorId: session.userId } });
  revalidatePath("/posts");
}

// app/posts/page.tsx (Server Component)
import { createPost } from "./actions";
export default function Posts() {
  return (
    <form action={createPost}>
      <input name="title" />
      <button type="submit">Create</button>
    </form>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 105 of 129 in Next.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Next.js questions
Up nextHard

How do you build a multi-tenant Next.js app with subdomain routing?

Continue