Blog
Software2024-06-0513 min

Patrones de Next.js App Router + Prisma que usamos en todos nuestros proyectos

Después de construir Verixo, OmniTrip, AAETAV y Tuki con el mismo stack, emergieron patrones repetibles que aceleran el desarrollo.

El stack que convergimos después de cuatro proyectos

Después de construir cuatro productos distintos con Next.js 14 App Router, Prisma y PostgreSQL, consolidamos un conjunto de patrones que usamos consistentemente.

Patrón 1: Prisma client singleton con logs configurables

El error más común con Prisma en Next.js es instanciar múltiples clientes en desarrollo, lo que agota las conexiones de la base de datos. La solución es un singleton que usa globalThis para persistir la instancia entre hot-reloads de Next.js.

Patrón 2: Server Actions con validación Zod en dos capas

Las Server Actions son endpoints HTTP reales: cualquiera puede llamarlas directamente. Nuestro patrón: validación con Zod tanto en el cliente como en el servidor. El schema de Zod se define una vez y se importa en ambos lugares.

Patrón 3: Rutas protegidas con middleware de Next.js

El middleware lee el JWT de la cookie, lo verifica, y si es inválido redirige al login. Si es válido, agrega headers con los datos del usuario que los Server Components leen sin tocar la base de datos.

Patrón 4: Server Components con Suspense para datos lentos

En lugar de mostrar un spinner global mientras carga toda la página, usamos Suspense de React para mostrar la página parcialmente mientras los datos lentos cargan en segundo plano. Next.js hace streaming del HTML enviando las partes estáticas primero.

Patrón 5: Invalidación de caché con revalidateTag

Asignamos tags a los queries de base de datos y los invalidamos en las Server Actions que mutan esos datos. Ejemplo en OmniTrip: cuando se crea una reserva, invalidamos el tag salidas-disponibilidad. El próximo usuario que visita el calendario ve los datos actualizados.

Lo que no usamos

tRPC: con Server Actions el overhead no vale la pena. Zustand o Redux para estado global: con Server Components, la mayoría del estado global vive en la URL o en la base de datos. Para el estado UI que queda, useState local es suficiente.