Lección 7 de 17 · Lectura y práctica
Práctica: Crear un CRUD con Server Actions
Tipo de lección: VideoConcepto claveLas Server Actions en Next.js 15 son funciones que se ejecutan exclusivamente en el servidor, permitiendo operaciones de datos seguras sin exponer APIs públicas. Piensa en ellas como cajeros.
Del concepto a la práctica
Taller de esta lección
Un CRUD completo exige conservar la identidad del registro y separar las cuatro operaciones. Usaremos tareas locales con identificadores numéricos: leer [1,2], crear el id 3, actualizar el id 2 y eliminar el id 1. El identificador no debe venir de un título editable.
Ejemplo resuelto
let tasks = [{ id: 1, text: 'Mapa' }, { id: 2, text: 'Pruebas' }]
export async function renameTask(id: number, text: string) {
const task = tasks.find(t => t.id === id)
if (!task || !text.trim()) return { ok: false }
task.text = text.trim(); return { ok: true, task }
}Renombrar 2 a Logs deja [Mapa, Logs].
Pruébalo
Lista los dos registros iniciales.
Crea un tercero con id único.
Actualiza solo el registro
2.Elimina el
1y vuelve a listar.
Comprueba tu resultado
Error frecuente: usar la posición del array como identidad. Corrígelo usando id. Resultado esperado final: quedan exactamente los registros 2 y 3; el 2 se llama Logs, y ninguna operación modifica accidentalmente el registro vecino.
Completa las cuatro operaciones del fixture
Este array mutable es una simulación de proceso: se pierde al reiniciar y no se comparte con otras instancias. No lo utilices como persistencia multiusuario. Un módulo de fixture marcado import 'server-only' puede exponer estas operaciones al servicio:
let tasks = [{ id: 1, text: 'Mapa' }, { id: 2, text: 'Pruebas' }]
let nextId = 3
export function listTasks() { return tasks.map(t => ({ ...t })) }
export function createTask(text: string) {
const value = text.trim(); if (!value) throw new Error('Texto requerido')
const task = { id: nextId++, text: value }; tasks.push(task); return { ...task }
}
export function renameTask(id: number, text: string) {
const i = tasks.findIndex(t => t.id === id)
if (i < 0 || !text.trim()) return { ok: false as const }
tasks[i] = { ...tasks[i], text: text.trim() }
return { ok: true as const, task: { ...tasks[i] } }
}
export function deleteTask(id: number) {
const i = tasks.findIndex(t => t.id === id); if (i < 0) return false
tasks = tasks.filter(t => t.id !== id); return true
}Parte de un proceso limpio: crea Evidencias (3), renombra 2 como Logs y elimina 1. listTasks devuelve 2/Logs y 3/Evidencias. Las Server Actions envuelven estas funciones después de comprobar sesión y tipos; revalida /tareas tras escribir. Para entregar el proyecto sustituye el fixture por almacenamiento duradero con autorización por registro.

Mapa de prácticaEl servidor puede obtener datos y producir el HTML inicial. El navegador muestra el resultado y ejecuta las interacciones que necesitan estado local. Mantén las claves sensibles en el servidor y define qué parte se ejecuta en cada entorno.
Ver la infografía en tamaño completo ↗Fuentes para profundizar
Tipo de lección: Video
Concepto clave
Las Server Actions en Next.js 15 son funciones que se ejecutan exclusivamente en el servidor, permitiendo operaciones de datos seguras sin exponer APIs públicas. Piensa en ellas como cajeros automáticos: tu aplicación cliente (el usuario) inserta una solicitud (como retirar dinero), pero toda la lógica de validación y procesamiento ocurre dentro del servidor (el banco), manteniendo la seguridad de las credenciales y el saldo.
En un CRUD tradicional con APIs REST, necesitas crear endpoints separados para cada operación (GET, POST, PUT, DELETE), lo que puede volverse complejo. Con Server Actions, defines funciones directas en tus componentes de servidor que manejan creación, lectura, actualización y eliminación en un solo lugar, reduciendo la sobrecarga de configuración. Esto es especialmente útil en aplicaciones full-stack donde la velocidad y la seguridad son prioritarias.
Cómo funciona en la práctica
Imagina que estás construyendo una app de tareas. Primero, creas un componente de servidor en app/tasks/page.js. Dentro, defines Server Actions usando 'use server' al inicio de la función. Por ejemplo, para agregar una tarea:
'use server';
export async function addTask(formData) {
const title = formData.get('title');
// Validar y guardar en base de datos
await db.tasks.create({ data: { title } });
revalidatePath('/tasks');
}Luego, en tu formulario cliente, llamas a esta acción con action={addTask}. Next.js maneja automáticamente la comunicación, enviando los datos del formulario al servidor, ejecutando la lógica y actualizando la UI con Streaming SSR para mostrar cambios en tiempo real sin recargar la página completa.
Caso de estudio
Vamos a aplicar esto a un sistema de inventario para una tienda online. Supongamos que tenemos una tabla de productos con estos datos:
| ID | Nombre | Precio | Stock |
|---|---|---|---|
| 1 | Laptop | 1200 | 10 |
| 2 | Mouse | 25 | 50 |
Creamos Server Actions en app/inventory/actions.js para manejar operaciones CRUD:
createProduct: Toma datos de un formulario y los inserta en la base de datos.getProducts: Recupera la lista de productos para mostrar en una tabla.updateProduct: Actualiza el precio o stock basado en ID.deleteProduct: Elimina un producto por ID, con validación de stock cero.
En la UI, usamos un formulario con action={createProduct} y una tabla que se actualiza dinámicamente gracias a revalidatePath. Esto permite al empleado de la tienda gestionar inventario en tiempo real, con feedback inmediato sobre errores como stock negativo.
Recuerda: Server Actions no reemplazan APIs públicas para integraciones externas, pero son ideales para operaciones internas donde controlas tanto el cliente como el servidor.
Errores comunes
- Olvidar 'use server': Si no incluyes esta directiva al inicio de tu función, Next.js intentará ejecutarla en el cliente, causando errores de seguridad o rendimiento. Siempre verifica que tus Server Actions estén marcadas correctamente.
- No validar datos de entrada: Confiar en datos del cliente sin sanitización puede llevar a inyecciones SQL o corrupción de datos. Usa bibliotecas como Zod para validar el
formDataantes de procesarlo. - Ignorar revalidación de caché: Después de mutar datos (como crear o actualizar), olvidar llamar a
revalidatePathorevalidateTaghace que la UI muestre información obsoleta. Inclúyelo siempre en tus acciones para mantener la coherencia. - Usar Server Actions para cargas pesadas: Estas acciones son para operaciones rápidas; tareas como procesamiento de imágenes grandes deben delegarse a jobs en segundo plano para no bloquear respuestas.
- Exponer lógica sensible en errores Mostrar mensajes de error detallados puede filtrar información de la base de datos. Envía errores genéricos al cliente y registra los detalles en el servidor.
Checklist de dominio
- Puedo crear una Server Action que maneje la creación de un recurso en una base de datos.
- Sé cómo estructurar acciones para lectura, actualización y eliminación en un solo archivo.
- Implemento validación de datos en el servidor antes de cualquier operación CRUD.
- Uso
revalidatePathorevalidateTagpara actualizar la UI después de mutaciones. - Diferencio cuándo usar Server Actions (operaciones internas) vs APIs públicas (integraciones externas).
- Manejo errores de forma segura, sin exponer detalles internos al cliente.
- Optimizo el rendimiento evitando acciones bloqueantes en flujos críticos.
Construye un CRUD de Usuarios con Server Actions
En este ejercicio, crearás un sistema de gestión de usuarios para una app interna. Sigue estos pasos:
- Configura un proyecto Next.js 15 con App Router y una base de datos SQLite usando Prisma.
- Define un modelo de Usuario en
prisma/schema.prismacon campos: id, nombre, email, y fecha de creación. - Crea un archivo
app/users/actions.jscon Server Actions para:createUser: Acepta nombre y email desde un formulario, valida que el email sea único, y guarda en la base de datos.getUsers: Recupera todos los usuarios ordenados por fecha de creación.updateUser: Permite actualizar el nombre de un usuario por ID.deleteUser: Elimina un usuario por ID, solo si no tiene registros asociados (simula con una validación básica).
- Implementa una página en
app/users/page.jsque:- Muestre una lista de usuarios en una tabla HTML, usando
getUsers. - Incluya un formulario para agregar nuevos usuarios, con
action={createUser}. - Añada botones para editar y eliminar usuarios, que llamen a las acciones correspondientes.
- Muestre una lista de usuarios en una tabla HTML, usando
- Prueba el flujo completo: agrega un usuario, edita su nombre, y elimínalo, verificando que la UI se actualice sin recargar.
Pistas
- Usa 'use server' al inicio de cada función en actions.js para asegurar ejecución en el servidor.
- Incluye revalidatePath('/users') en tus acciones de creación, actualización y eliminación para refrescar la lista automáticamente.
- Para validar el email único, consulta la base de datos en createUser antes de insertar, y devuelve un error amigable si ya existe.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.
Sigue con Next.js 15: Aplicaciones Full-Stack con Server Components y Streaming SSR
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.