// app/actions.ts"use server";import { db } from "@/lib/db";import { revalidatePath } from "next/cache";export async function createPost(formData: FormData) { const title = formData.get("title") as string; const body = formData.get("body") as string; await db.insert("posts", { title, body, createdAt: new Date() }); revalidatePath("/posts");}
// app/posts/NewPostForm.tsx"use client";import { createPost } from "../actions";export default function NewPostForm() { return ( <form action={createPost}> <input name="title" placeholder="Title"
Cuándo usarlo: Usa Acciones del Servidor para cualquier mutación de datos (crear, actualizar, eliminar) que necesite ejecutarse en el servidor -- escrituras en la base de datos, cargas de archivos, envío de emails, llamadas a APIs de terceros con secretos.
// Una aplicación de tareas completa con acciones del servidor, validación y manejo de errores// app/actions.ts"use server";import { z } from "zod";import { db } from "@/lib/db";import { revalidatePath } from "next/cache";const TodoSchema = z.object({ text: z.string
// app/todos/TodoApp.tsx"use client";import { useActionState, useOptimistic, useTransition } from "react";import { addTodo, toggleTodo, deleteTodo, type ActionResult } from "../actions";type Todo = { id: string; text: string; completed:
Lo que esto demuestra:
Un archivo "use server" que exporta múltiples acciones del servidor
Validación con Zod dentro de una acción del servidor
Retorno de resultados estructurados (éxito/error) de acciones
Vinculación de una acción del servidor a useActionState para gestión de estado de formularios
Llamada de acciones del servidor desde manejadores de eventos a través de startTransition
Actualizaciones optimistas superpuestas sobre acciones del servidor
Una función (o archivo) marcada con "use server" le dice al empaquetador que cree un punto final de red (RPC) para esa función. El cliente recibe un ID de referencia, no el cuerpo de la función.
Cuando un cliente llama una acción del servidor, React serializa los argumentos, envía un POST HTTP al servidor, ejecuta la función y devuelve el resultado serializado.
Las acciones del servidor se pueden usar de dos formas: (1) pasadas a <form action={}> donde React automáticamente recopila FormData, o (2) llamadas directamente como await deleteItem(id) dentro de un startTransition.
Los argumentos y valores de retorno deben ser serializables -- las mismas reglas que aplican para props de Componentes del Servidor aplican.
Las acciones del servidor se ejecutan secuencialmente por defecto por solicitud. Los envíos de formularios múltiples se encolan, no se ejecutan en paralelo.
En marcos como Next.js, revalidatePath o revalidateTag provoca el re-renderizado de Componentes del Servidor afectados después de que la acción se complete.
Acciones del servidor en línea en Componentes del Servidor:
// La acción se define en línea y se cierra sobre datos del lado del servidorexport default async function LikePage() { let likes = await db.getLikes(); async function addLike() { "use server"; await db.incrementLikes(); } return (
Llamar acciones del servidor fuera de formularios:
"use client";import { useTransition } from "react";import { deleteItem } from "./actions";function DeleteButton({ id }: { id: string }) { const [isPending, startTransition] =
Vinculación de argumentos adicionales con .bind:
// Aplicación parcial del id para que el formulario solo envíe FormDataimport { updateItem } from "./actions";function EditForm({ id }: { id: string }) { const updateWithId = updateItem.bind(null, id); return ( <form
Las acciones del servidor deben ser async -- La directiva "use server" requiere que la función sea async. Solución: Siempre declara acciones del servidor con async function.
Los argumentos deben ser serializables -- No puedes pasar nodos del DOM, instancias de clases, u objetos no serializables. Solución: Extrae los datos serializables que necesitas (strings, números, IDs) antes de llamar la acción.
Lanzar errores en acciones -- Si una acción del servidor lanza, el error cruza el límite de red y puede bloquear el cliente. Solución: Captura errores dentro de la acción y devuelve un objeto de resultado. Usa límites de error como red de seguridad.
Las acciones se encolan secuencialmente -- Los envíos de formularios rápidos se encolan, no se paralelizan. La interfaz puede sentirse lenta. Solución: Usa useOptimistic para actualizar la interfaz inmediatamente mientras las acciones se procesan en orden.
Captura de cierre en acciones en línea -- Las acciones del servidor en línea se cierran sobre variables del lado del servidor en el momento del renderizado. Esos valores se serializan y se envían al cliente como argumentos ocultos cifrados. Solución: Ten en cuenta que los cierres aumentan el tamaño de la carga. Prefiere archivos de acciones para lógica compleja.
Sin acceso a encabezados de solicitud por defecto -- Las acciones del servidor no reciben automáticamente cookies o encabezados como argumentos. Solución: Usa ayudantes proporcionados por el marco como cookies() o headers() de next/headers dentro del cuerpo de la acción.
¿Marca "use server" un archivo como un Componente del Servidor?
No -- esto es un malentendido común."use server" marca Funciones del Servidor (Acciones del Servidor), no Componentes del Servidor.
Los Componentes del Servidor son el defecto en React 19 / Next.js App Router -- no se necesita directiva.
Solo agregas "use client" para optar por no usar Componentes del Servidor.
"use server" es exclusivamente para funciones que se ejecutan en el servidor pero son llamadas desde código cliente (formularios, manejadores de eventos).
Poner "use server" en la parte superior de un archivo de componente convertirá cada exportación en una Acción del Servidor, no un Componente del Servidor -- y generará error porque los componentes no son acciones válidas.
¿Qué hace la directiva "use server"?
Le dice al empaquetador que cree un punto final de red (RPC) para la función
El cliente recibe un ID de referencia, no el cuerpo de la función
Cuando se llama desde el cliente, React serializa argumentos, envía un POST HTTP, ejecuta en el servidor y devuelve el resultado serializado
¿Pueden usarse acciones del servidor fuera de formularios?
Sí. Las acciones del servidor se pueden llamar directamente desde manejadores de eventos envueltos en startTransition:
¿Cómo desencadenas revalidación después de que una acción del servidor se completa?
En Next.js, usa revalidatePath("/path") o revalidateTag("tag") dentro de la acción del servidor
Esto desencadena re-renderizado de Componentes del Servidor afectados con datos frescos
La revalidación se ejecuta después de que la función de acción devuelve
¿Se procesan múltiples envíos de formularios en paralelo?
No. Las acciones del servidor se ejecutan secuencialmente por defecto por solicitud
Los envíos de formularios rápidos se encolan, no se paralelizan
Usa useOptimistic para actualizar la interfaz inmediatamente mientras las acciones se procesan en orden
Trampa: ¿Qué sucede si una acción del servidor lanza un error?
El error cruza el límite de red y puede bloquear el cliente
Siempre captura errores dentro de la acción y devuelve un objeto de resultado en lugar de lanzar
Usa límites de error como red de seguridad para fallos inesperados
Trampa: ¿Puedes pasar una función regular (no una acción del servidor) desde un Componente del Servidor a un Componente Cliente?
No. Solo funciones marcadas con "use server" son serializables a través del límite servidor-cliente
Los cierres regulares, instancias de clases y nodos del DOM no se pueden pasar como props a Componentes Cliente
Extrae los datos serializables que necesitas (strings, números, IDs) antes de pasar
¿Cuál es la diferencia entre acciones del servidor en línea y archivos de acciones?
Las acciones en línea se definen dentro de un Componente del Servidor con "use server" dentro del cuerpo de la función; se cierran sobre variables del lado del servidor en el momento del renderizado
Los archivos de acciones tienen "use server" en la parte superior del archivo y exportan múltiples acciones
Los cierres en línea aumentan el tamaño de la carga porque los valores capturados se serializan; prefiere archivos de acciones para lógica compleja
¿Cómo escribes una acción del servidor usada con useActionState en TypeScript?