The mutationserver actions & cookies

What if the form just called the function?

It does now. A Server Action runs on the server and plugs straight into a form’s action: no endpoint to design, no fetch to write, no JSON contract to keep in sync. Add one to the count and follow it: the form calls the function, the function writes the new count, and Next.js re-renders the page around it. That is the whole thing.

The count lives in a cookie your browser carries but your JavaScript cannot open, which is what httpOnly means, and a Server Component reads it back. The value is safe from the tab that displays it, without a line written to arrange that.

live

reading your cookie on the server…

the form posts to the function · the function writes the cookie · the page re-renders around it, with or without JavaScript

actions.ts + mutation-panel.tsx
// actions.ts — the entire backend of this demo
"use server";

export async function pressTheButton() {
  const jar = await cookies();
  const count = parseCount(jar.get("playground-presses")?.value) + 1;
  jar.set("playground-presses", String(count), { httpOnly: true });
  // Cookie changed, so Next.js re-renders this page's server tree —
  // the count you see is read back on the server, not tracked in JS.

  // The request view is drawn from what this function saw:
  const incoming = await headers();
  return {
    actionId: incoming.get("next-action"), // the function's id — the route
    contentType: incoming.get("content-type"), // multipart/form-data
    count,
  };
}

// mutation-panel.tsx — the entire frontend
const [receipt, formAction, pending] = useActionState(pressTheButton, null);

return <form action={formAction}>{/* a button */}</form>;