# Nextjs Server Actions

> Mutations, Form handling, and RPC-style calls. Use when implementing Server Actions, form mutations, or RPC-style data mutations in Next.js. (triggers: app/**/actions.ts, src/app/**/actions.ts, app/**/*.tsx, src/app/**/*.tsx, use server, Server Action, revalidatePath, useFormStatus)

- Skill: `comeonoliver/nextjs-server-actions` (Agent Skill)
- Install (CLI): `npx skillmds@latest add comeonoliver/nextjs-server-actions`
- Raw SKILL.md: https://api.skillmd.com/api/skills/comeonoliver/nextjs-server-actions/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: ComeOnOliver (https://skillmd.com/u/comeonoliver)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/comeonoliver/nextjs-server-actions

---


# Server Actions

## **Priority: P1 (HIGH)**

> [!WARNING]
> If the project uses the `pages/` directory instead of the App Router, **ignore** this skill entirely.

Handle form submissions and mutations without creating API endpoints.

## Implementation Guidelines

- **Directive**: Always start the file or function with `'use server'`. Access `formData.get('title')` for typed form fields. Export async functions for mutations.
- **Form Handling**: Use the `action` prop of `<form>` to trigger actions via `action={createPost}`. Use `useFormStatus()` for `pending` states — `disabled={pending}` on buttons. Use `useActionState` (React 19/Next.js 15) for `action={action}` form state with `<form action={action}>`.
- **Data Refresh**: Trigger UI updates using **`revalidatePath('/')`** or **`revalidateTag('tag-name')`** after a successful mutation.
- **Interactivity**: For non-form triggers, invoke actions using the **`useTransition`** hook to handle loading UI and prevent the page from blocking.
- **Optimistic Updates**: Use **`useOptimistic`** to show the expected UI state immediately before the server confirms the mutation.
- **Security**: **Sanitize all inputs** from `FormData`. Perform **auth checks** inside every action (`await auth()`). Limit file uploads by size and MIME type.

- **Form**: `<form action={createPost}>` (Progressive enhancements work without JS).
- **Event Handler**: `onClick={() => createPost(data)}`.
- **Pending State**: Use `useFormStatus` hook (must be inside a component rendered within the form).

## **P1: Operational Standard**

### **1. Secure & Validate**

Always validate inputs with `z.object({` schema and `safeParse` before processing. Check authorization within the action. See [Secure Action Example](references/secure-actions.md).

### **2. Pending States**

Use `useActionState` (React 19/Next.js 15+) for state handling and `useFormStatus` for button loading states.

## **Constraints**

- **Closures**: Avoid defining actions inside components to prevent hidden closure encryption overhead and serialization bugs.
- **Redirection**: Use `redirect()` for success navigation; it throws an error that Next.js catches to handle the redirect.

## Anti-Patterns

- **No unvalidated Server Action inputs**: Always validate with Zod before processing.
- **No skipped auth checks**: Verify session/user inside every action, not just middleware.
- **No actions defined inside components**: Define in `actions.ts` to avoid closure bugs.
- **No `redirect()` in try/catch**: `redirect()` throws; catching it suppresses the redirect.


