Server Actions = mutation endpoints, declared inline
A Server Action is an async function that runs on the server but is callable from a Client Component. The framework wires it as a unique POST endpoint behind the scenes — you call it like a function, not like an API.
Two ways to declare
| Approach | How |
|---|---|
| File-level | 'use server' at the top of the file. Every exported function in that file is an action. |
| Inline | Inside a Server Component, define the function and put 'use server' at the top of its body. |
What they replace
For internal CRUD, you no longer need /api/…/route.ts + fetch() + JSON parsing on both sides. Server Actions are POST endpoints with built-in CSRF protection, encrypted action IDs, and automatic dead-code elimination of unused actions.
What they don't replace
Public APIs (third parties call them), webhooks, integrations, and anything that needs to expose a stable URL still belong in Route Handlers (covered in the next track).
Keep the mutation transaction legible in one place: parse input, read the session, authorize the resource, write, and invalidate affected reads. Group actions by feature so multiple forms can reuse the same domain change without building one unrelated global action file.
A function-shaped call is still a network POST. It can be delayed, retried, duplicated, or invoked outside your UI. Payments and orders need idempotency keys or database constraints just as a conventional endpoint would. Implement one internal mutation both as Route Handler plus fetch and as a Server Action. Compare boilerplate and network surfaces while ensuring validation, authorization, duplicate submission behavior, and cache updates remain explicit.