# Server Actions de Next.js 16 en 2026: mutaciones, revalidación y preguntas de entrevista
> Cómo las Server Actions de Next.js 16 manejan mutaciones, revalidación, estado pendiente, UI optimista y seguridad, con las preguntas de entrevista que evalúan cada concepto.
- Published: 2026-06-24
- Updated: 2026-07-06
- Author: SharpSkill
- Tags: next.js, server-actions, react, mutations, revalidation, interview
- Reading time: 11 min
---
Las Server Actions de Next.js convierten una simple función asíncrona en un endpoint de mutación del lado del servidor que un formulario puede invocar directamente, sin ruta de API, sin `fetch` del cliente y sin serialización manual de JSON. En Next.js 16 son la forma predeterminada de escribir mutaciones de datos y aparecen en casi toda entrevista senior de React en 2026. Este análisis a fondo desglosa cómo se ejecutan, cómo la revalidación propaga datos frescos a la interfaz, cómo modelar los estados pendiente y de error, y las reglas de seguridad que hacen tropezar a la mayoría de los desarrolladores.
> **Definición en una frase**
>
> Una Server Action es una función asíncrona marcada con `"use server"` que se ejecuta solo en el servidor y puede invocarse desde un componente de cliente o un formulario como si fuera local, mientras Next.js gestiona automáticamente la petición de red, la serialización de argumentos y la protección CSRF.
## Cómo se ejecutan las Server Actions internamente
Una Server Action es una función exclusiva del servidor que se invoca por la red a través de un endpoint generado por el compilador. Cuando una función lleva la directiva `"use server"`, el compilador de Next.js nunca envía su cuerpo al navegador. En su lugar, reemplaza la función por una referencia ligera: un ID de acción con hash asociado a una ruta POST generada. Al invocar la acción desde el cliente se envía una petición a esa ruta, la función real se ejecuta en el servidor y el resultado serializado regresa en streaming a quien la llamó.
Este diseño tiene tres consecuencias que conviene recordar tanto para el código de producción como para las entrevistas. Primero, los argumentos y los valores de retorno deben ser serializables, porque cruzan la red como cargas útiles codificadas. Segundo, los secretos permanecen en el servidor, ya que el cuerpo de la función nunca se empaqueta para el cliente. Tercero, las acciones asociadas a un `
)
}
```
El atributo `name` de cada campo se convierte en la clave que lee `formData.get()`. La [referencia de FormData en MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData) explica cómo el navegador construye este objeto a partir del formulario. Para un control más amplio, `next/form` extiende el elemento nativo con navegación del lado del cliente y prefetching, manteniendo el mismo contrato basado en acciones.
## Gestionar el estado pendiente y de error con useActionState
Los formularios reales necesitan retroalimentación de validación y un indicador de carga. El hook `useActionState` de React 19 envuelve una Server Action, propaga un valor de estado a través de cada envío y expone una bandera `isPending`. Sustituye al antiguo nombre `useFormState` y devuelve una tupla con el estado actual, una acción envuelta y el booleano de pendiente.
```tsx
// app/posts/new-post-form.tsx
"use client"
import { useActionState } from "react"
import { createPost } from "./actions"
const initialState = { error: "" }
export default function NewPostForm() {
// state carries the last return value; isPending tracks the in-flight request
const [state, formAction, isPending] = useActionState(createPost, initialState)
return (
)
}
```
Cuando un hook maneja la acción, la firma de la función incorpora un primer parámetro `prevState` antes de `FormData`. Devolver un objeto en lugar de lanzar una excepción permite que el componente muestre la validación en línea sin necesidad de un error boundary:
```typescript
// app/posts/actions.ts
"use server"
import { revalidateTag } from "next/cache"
import { PostService } from "@/lib/services/post-service"
type FormState = { error: string }
export async function createPost(
prevState: FormState,
formData: FormData,
): Promise {
const title = formData.get("title") as string
// Validate on the server; client validation is never trustworthy alone
if (!title || title.length < 3) {
return { error: "Title must be at least 3 characters." }
}
await PostService.create({ title })
// Invalidate by tag rather than path for finer-grained control
revalidateTag("posts")
return { error: "" }
}
```
La [referencia de useActionState en react.dev](https://react.dev/reference/react/useActionState) cubre patrones avanzados como el soporte de permalinks para envíos previos a la hidratación. Devolver un estado estructurado mantiene el camino feliz y el camino de error en un mismo lugar predecible.
## revalidatePath vs revalidateTag: elegir la invalidación correcta
Una mutación es solo la mitad del trabajo; la interfaz debe reflejarla. Next.js expone dos funciones de invalidación desde `next/cache`, y elegir la correcta es un discriminador frecuente en las entrevistas.
| Función | Invalida | Mejor cuando |
|----------|-------------|-----------|
| `revalidatePath("/posts")` | Toda entrada cacheada de una ruta | La mutación afecta a una página o layout claro |
| `revalidateTag("posts")` | Todo fetch cacheado etiquetado con ese tag | Los mismos datos aparecen en varias rutas |
`revalidatePath` es de grano grueso y centrada en rutas: limpia la caché de una URL y su árbol de layouts. `revalidateTag` es granular y centrada en datos: cualquier `fetch` o función cacheada etiquetada con la cadena se purga esté donde esté. Los tags escalan mejor en aplicaciones grandes porque una sola mutación puede refrescar una barra lateral, un listado y una página de detalle en una única llamada. Ambas funciones marcan los datos como obsoletos en lugar de volver a solicitarlos de inmediato, de modo que la siguiente petición regenera el contenido.
Con los Cache Components de Next.js 16, el etiquetado se integra con la directiva `"use cache"` mediante `cacheTag`, lo que cambia la forma de razonar sobre el cacheo en toda la aplicación. Esa interacción se aborda en profundidad en la [guía de Cache Components de Next.js 16](/blog/react-next/nextjs-16-cache-components-use-cache-ppr-interview-questions) en SharpSkill.
## Actualizaciones optimistas de la UI con useOptimistic
Los viajes de ida y vuelta por la red añaden una latencia perceptible. El hook `useOptimistic` renderiza el resultado esperado al instante y luego lo reconcilia con la respuesta del servidor una vez que la acción se resuelve. Recibe el estado actual y un reducer que produce la versión optimista.
```tsx
// app/posts/like-button.tsx
"use client"
import { useOptimistic } from "react"
import { likePost } from "./actions"
export function LikeButton({ postId, likes }: { postId: string; likes: number }) {
// optimisticLikes updates before the server confirms
const [optimisticLikes, addOptimisticLike] = useOptimistic(
likes,
(current) => current + 1,
)
async function handleLike() {
addOptimisticLike(null) // update the UI immediately
await likePost(postId) // then run the real mutation
}
return (
)
}
```
Si la acción falla, React revierte automáticamente el valor optimista al estado confirmado por el servidor, por lo que no hace falta un rollback manual. La [referencia de useOptimistic en react.dev](https://react.dev/reference/react/useOptimistic) detalla cómo el ciclo de reconciliación interactúa con las transiciones. Este patrón es lo que hace que los formularios con Server Actions se sientan tan responsivos como una SPA renderizada por completo en el cliente.
## Enlazar argumentos e invocar acciones desde manejadores de eventos
No toda mutación se origina en el envío de un formulario. Eliminar una fila, alternar una configuración o reordenar una lista suele dispararse desde el clic de un botón u otro evento. Una Server Action es una referencia de función normal en el cliente, así que puede invocarse desde cualquier manejador, siempre que la llamada se ejecute dentro de una transición para mantener la interfaz responsiva.
Los argumentos adicionales que no son campos del formulario se adjuntan con `bind`, que produce una nueva acción con esos valores antepuestos. Esta es la forma idiomática de pasar un ID junto con el `FormData` enviado.
```tsx
// app/posts/post-actions.tsx
"use client"
import { useTransition } from "react"
import { deletePost, updatePost } from "./actions"
export function PostActions({ postId }: { postId: string }) {
const [isPending, startTransition] = useTransition()
// Bind the id so the action receives it before FormData
const updateWithId = updatePost.bind(null, postId)
return (
{/* Event-handler invocation wrapped in a transition */}
)
}
```
Los argumentos enlazados se cifran como cualquier otro valor capturado por el closure, de modo que el `postId` no se manipula en tránsito, aunque la acción debe confirmar de todas formas que quien la invoca tiene permiso para actuar sobre ese registro. Envolver la llamada directa en `startTransition` permite que React mantenga la interfaz interactiva y exponga el estado pendiente sin necesidad de un formulario.
## Seguridad de las Server Actions: trata cada acción como una API pública
El malentendido más peligroso es creer que una Server Action es privada porque se escribe junto al código del servidor. En realidad, una vez que una acción se utiliza, Next.js genera un endpoint POST público que cualquiera puede invocar con una petición manipulada. El framework proporciona IDs de acción seguros y elimina las acciones sin uso durante `next build`, pero no autoriza a quien la invoca.
> **Autoriza dentro de cada acción**
>
> Las Server Actions son endpoints HTTP accesibles. Las comprobaciones de sesión en un layout o en el middleware no las protegen, porque un atacante puede hacer un POST directamente a la acción. Es necesario verificar la sesión y los permisos de quien la invoca dentro del cuerpo de la acción antes de tocar cualquier dato.
```typescript
// app/admin/actions.ts
"use server"
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { UserService } from "@/lib/services/user-service"
export async function deleteUser(userId: string) {
// Authenticate on every invocation, not in a wrapper component
const session = await auth.api.getSession({ headers: await headers() })
if (!session || session.user.role !== "admin") {
throw new Error("Unauthorized")
}
await UserService.delete(userId)
}
```
Hay dos reglas más que importan. Los valores capturados por el closure de una acción en línea se cifran antes de enviarse al cliente y se descifran en el servidor, de modo que un token capturado no se filtra en texto plano, pero depender de ello es frágil: lo mejor es mantener los secretos completamente fuera de los closures. Y cualquier argumento que provenga del cliente es entrada no confiable que debe validarse, igual que el cuerpo de una petición REST. La [guía de seguridad de datos de Next.js](https://nextjs.org/docs/app/guides/data-security) formaliza el modelo de taint que respalda estas garantías. Para practicar de forma estructurada estos compromisos, el [módulo de entrevista sobre Server Actions de Next.js](/technologies/react-next/interview-questions/nextjs-server-actions) en SharpSkill repasa exactamente las preguntas que hacen los paneles de contratación.
## Preguntas de entrevista sobre Server Actions de Next.js 16
Estas preguntas aparecen una y otra vez en los procesos senior de React y full-stack de 2026.
**¿Por qué una Server Action solo puede aceptar y devolver valores serializables?** Porque los argumentos y los resultados cruzan la frontera de red entre el cliente y el servidor como cargas útiles codificadas. Las funciones, las instancias de clase y los nodos del DOM no pueden serializarse, así que pasarlos lanza un error. `FormData`, los objetos planos, los arreglos y los primitivos son seguros.
**¿Cómo funciona la mejora progresiva con las Server Actions?** Cuando una acción se pasa directamente a la prop `action` de un formulario, el navegador envía el formulario de forma nativa mediante una petición POST incluso antes de que React se hidrate. Next.js intercepta y ejecuta la acción en el servidor, de modo que el formulario es funcional sin JavaScript en el cliente y evoluciona hacia una experiencia impulsada por el cliente tras la hidratación.
**¿Cuál es la diferencia entre lanzar y devolver un error en una acción?** Lanzar propaga el error al error boundary más cercano y es lo adecuado para fallos inesperados. Devolver un objeto de estado estructurado a través de `useActionState` es lo adecuado para errores de validación esperados que deben mostrarse en línea sin desmontar el formulario.
**¿Llamar a revalidatePath vuelve a solicitar los datos de inmediato?** No. Marca las entradas cacheadas como obsoletas para que la siguiente petición las regenere. La respuesta actual no se ve afectada, razón por la cual una redirección tras una mutación aterriza en contenido recién renderizado.
Para el contexto de renderizado más amplio dentro del cual se ejecutan estas mutaciones, el análisis de [React 19 Server Components en producción](/blog/react-next/react-19-server-components-production) complementa de forma natural el conocimiento de las Server Actions.
## Conclusión
Las Server Actions de Next.js 16 consolidan las mutaciones, la revalidación y la mejora progresiva en una única primitiva orientada al servidor. Las conclusiones clave:
- Marcar las mutaciones con `"use server"` y pasarlas a la prop `action` de un formulario para obtener gratis la gestión de red y la mejora progresiva.
- Manejar el estado pendiente y de validación con `useActionState`, devolviendo un objeto estructurado para los errores esperados en lugar de lanzar excepciones.
- Recurrir a `revalidatePath` cuando cambia una ruta y a `revalidateTag` cuando los mismos datos abarcan varias rutas.
- Usar `useOptimistic` para renderizar el resultado esperado al instante y dejar que React reconcilie o revierta automáticamente.
- Autorizar y validar dentro del cuerpo de cada acción, porque cada acción utilizada es un endpoint HTTP público que el middleware por sí solo no protege.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/es/blog/react-next/nextjs-16-server-actions-mutations-revalidation-interview-questions