Module P-2·25 min read

How Server Actions are compiled, useActionState (the useFormState replacement), useOptimistic for instant UI, the after() API for post-response side effects, and Zod validation patterns.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

P-2 — Server Actions: Mutations Done Right

Who this is for: Practitioners who understand data fetching from P-1 and need to handle the other side of the equation — user-initiated mutations. Server Actions are how the App Router handles form submissions, data updates, and any write operation originating from the client. This module covers the full picture: how they actually work, the security implications most tutorials skip, and the patterns that make forms feel instant.


What Server Actions Actually Are

The name "Server Action" sounds like a special framework concept, but the mechanics are simpler than the name implies.

When you mark a function with 'use server', Next.js does three things at build time:

  1. Moves the function to the server bundle. The code never reaches the browser.
  2. Generates an endpoint. Next.js creates a unique POST endpoint for this function — the URL is a hash derived from the function's location, not a human-readable path.
  3. Creates a stub on the client. Instead of the function itself, the browser gets a small proxy that makes a POST request to that endpoint when called.

From the developer's perspective, you call a function. Under the hood, you're making an HTTP POST to an automatically generated endpoint. The function body executes on the server. The result is serialized and sent back to the client.

This is why Server Actions can only receive and return serializable values — they cross the network.


Defining Server Actions

Inline in a Server Component:

tsx

In a dedicated actions file:

ts

The file-level 'use server' directive is more maintainable for production codebases — all actions in one place, no risk of accidentally marking a utility function as a Server Action.


The Security Implications Nobody Talks About

Server Actions are HTTP endpoints. They're POST endpoints, but they're public — nothing stops someone from calling them directly with curl or Postman. There is no automatic authentication on Server Actions.

This is the most dangerous misconception about Server Actions: because they look like private functions, engineers sometimes assume they're protected by default.

Always authenticate inside Server Actions that touch sensitive data:

ts

Validate all inputs. FormData.get() returns string | File | null. Treat it like untrusted user input from an external API, because that's exactly what it is:

ts

z.coerce.number() converts the string "29.99" from FormData into the number 29.99. Always coerce and validate, never cast.


useActionState — Form State Management

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.