Prisma con Next.js 15: Integración Completa con App Router (2026)
Cómo integrar Prisma con Next.js 15 y el App Router: singleton, Server Components, Server Actions, Edge Runtime y connection pooling con ejemplos reales.
Integrar Prisma con Next.js 15 requiere tres pasos concretos: instalar prisma y @prisma/client, definir tu esquema en schema.prisma y exportar una instancia singleton del cliente que puedas importar desde Server Components y Server Actions del App Router. Llevo usando Prisma en proyectos Next.js desde la época del pages/ router, y en 2026 el ORM se lleva especialmente bien con la nueva arquitectura de componentes de servidor: consultas tipadas en el servidor, cero JavaScript enviado al cliente, y (si usas Prisma Postgres o Accelerate) compatibilidad completa con Edge Runtime.
Prisma 6.x es compatible con Next.js 15 y React 19 sin flags experimentales; solo necesitas Node.js 18.18 o superior.
El error más común en desarrollo, "Too many PrismaClient instances", se resuelve con un singleton global que sobrevive al Hot Module Replacement.
El cliente de Prisma tradicional NO funciona en Edge Runtime; para middleware o rutas edge necesitas Prisma Accelerate o Prisma Postgres.
Con App Router puedes llamar prisma.model.findMany() directamente dentro de un Server Component asíncrono, sin getServerSideProps.
Server Actions más Prisma es el patrón recomendado para mutaciones: menos código, tipos de extremo a extremo y revalidación integrada con revalidatePath.
Para producción usa un pooler (PgBouncer, Prisma Accelerate o el pooler nativo de tu proveedor) porque las funciones serverless abren una conexión por invocación.
Instalar Prisma en un proyecto Next.js 15
Empieza con un proyecto Next.js 15 recién creado o uno existente. La instalación son dos paquetes: prisma como dependencia de desarrollo (la CLI) y @prisma/client como dependencia de producción (el cliente que ejecuta las queries). Después ejecutas prisma init para generar el archivo schema.prisma y el .env con la variable DATABASE_URL.
Esto crea prisma/schema.prisma. Define un modelo mínimo para probar que todo funciona. En mi caso una tabla Post con dos campos:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
createdAt DateTime @default(now())
}
Aplica el esquema a tu base de datos y genera el cliente tipado:
npx prisma migrate dev --name init
# Esto genera automáticamente @prisma/client en node_modules
Cómo evitar múltiples instancias de PrismaClient en desarrollo
Este es el footgun clásico. En desarrollo, cada vez que Next.js recarga un módulo por HMR, se instancia un new PrismaClient() nuevo. Después de treinta ediciones tienes treinta clientes vivos, cada uno con su propio pool de conexiones, y PostgreSQL empieza a rechazarte con "too many connections". La solución es guardar el cliente en globalThis, que sobrevive a los reloads.
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
En producción cada instancia serverless crea su propio cliente al arrancar en frío, así que la comprobación NODE_ENV !== 'production' es lo que impide contaminar el globalThis serverless. Este archivo lo importas en todos los Server Components y Server Actions que necesiten acceder a la base de datos.
Consultar la base de datos desde Server Components
La ventaja más grande del App Router es que puedes hacer await prisma.post.findMany() directamente dentro del componente. Nada de getServerSideProps, nada de rutas API intermediarias. Si vienes del pages router, este cambio de mentalidad es liberador: el componente es la capa de datos. Para más contexto sobre este modelo revisa mi guía de React Server Components y obtención de datos en Next.js 15.
Por defecto Next.js 15 marca esta ruta como dinámica (SSR en cada request) porque detecta acceso a base de datos externa. Si quieres ISR con revalidación temporal, exporta revalidate:
// Regenerar la página cada 60 segundos
export const revalidate = 60
Para decidir entre SSG, ISR, SSR y PPR con este tipo de consultas, consulta la guía comparativa de estrategias de renderizado en Next.js 15. En proyectos reales suelo empezar con ISR de 60 segundos y bajar el intervalo solo si los datos lo justifican.
Streaming con Suspense
Si tu consulta es lenta, envuélvela en <Suspense> para renderizar el shell inmediatamente y hacer stream de los datos cuando lleguen. Mejora el TTFB percibido sin cambiar tu lógica de datos:
Para crear, actualizar o borrar registros, Server Actions es el patrón que recomiendo. Reemplaza la mayoría de las rutas API tradicionales. La acción se ejecuta en el servidor, valida la entrada, invoca Prisma, y luego llama a revalidatePath para que el Server Component se re-renderice con los datos frescos. Cubro todo el patrón en profundidad en la guía de Server Actions en Next.js 15.
// app/posts/actions.ts
'use server'
import { prisma } from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { z } from 'zod'
const CreatePostSchema = z.object({
title: z.string().min(3).max(120),
content: z.string().min(10),
})
export async function createPost(formData: FormData) {
const parsed = CreatePostSchema.safeParse({
title: formData.get('title'),
content: formData.get('content'),
})
if (!parsed.success) {
return { error: parsed.error.flatten().fieldErrors }
}
const post = await prisma.post.create({
data: { ...parsed.data, published: true },
})
revalidatePath('/posts')
redirect(`/posts/${post.id}`)
}
El formulario es un simple <form action={createPost}>. La validación con Zod protege de datos malformados; sin ella, cualquier POST manipulado puede insertar filas basura. Honestamente, trato la validación como no-negociable en cualquier Server Action que toque la base de datos.
¿Es Prisma compatible con Edge Runtime?
Respuesta corta: el cliente Prisma tradicional NO corre en Edge Runtime. Depende de motores nativos (Rust binaries o WASM con Node.js APIs) que no existen en el entorno V8-isolate de Edge. Si intentas importar @prisma/client desde un middleware.ts o una ruta con export const runtime = 'edge', tu build fallará con "PrismaClient is unable to run in this browser environment". Me choqué con este error en producción la primera vez que moví un route handler a edge, así que ojo con esto.
Las tres soluciones oficiales en 2026 son:
Prisma Accelerate: un proxy HTTP que envuelve tu base de datos existente. El cliente edge llama a Accelerate por HTTP en lugar de hablar TCP directo con PostgreSQL. Incluye connection pooling global.
Prisma Postgres: la base de datos serverless propia de Prisma, lanzada en acceso general en 2025. Compatible con Edge de fábrica, sin configuración extra.
Driver adapters: usa el driver serverless de tu proveedor (Neon serverless driver, PlanetScale HTTP driver) con el adaptador Prisma correspondiente.
// Con Prisma Accelerate
import { PrismaClient } from '@prisma/client/edge'
import { withAccelerate } from '@prisma/extension-accelerate'
export const prisma = new PrismaClient().$extends(withAccelerate())
// En tu route handler edge
export const runtime = 'edge'
export async function GET() {
const posts = await prisma.post.findMany({
cacheStrategy: { ttl: 60 }, // caché edge de 60s
})
return Response.json(posts)
}
Para middleware sigo recomendando NO tocar la base de datos. Mejor haz la comprobación de sesión con un JWT firmado (más rápido, sin roundtrip a la DB). Los detalles de ese patrón están en la guía de Middleware en Next.js 15.
Connection pooling para producción
Aquí es donde muchos proyectos se rompen al pasar a producción. Cada función serverless de Vercel abre una nueva conexión Prisma en el arranque en frío. Con tráfico moderado puedes saturar el límite de conexiones de PostgreSQL (por defecto 100 en instancias pequeñas de Supabase o Neon) y ver errores P1001 intermitentes. Me pasó en un proyecto justo la noche de un lanzamiento, así que aprendí a configurar el pool antes de hacer el primer deploy.
Opciones de pooling en 2026
Opción
Compatible Edge
Setup
Coste
Cuándo usarlo
PgBouncer (Supabase, Neon)
No
URL con ?pgbouncer=true
Incluido
Runtime Node.js, DB gestionada
Prisma Accelerate
Sí
Extensión + URL de Accelerate
Free tier + de pago
Necesitas edge o caché global
Prisma Postgres
Sí
Un solo comando
Free tier generoso
Proyectos nuevos, sin migración
Neon serverless driver
Sí
Adapter Prisma
Incluido en Neon
Ya usas Neon
Si ya tienes una base de datos y quieres el mínimo cambio, PgBouncer en modo transaction con ?pgbouncer=true&connection_limit=1 en el DATABASE_URL resuelve el 90% de los casos. La documentación oficial de Prisma sobre PgBouncer tiene los detalles finos, incluidas las incompatibilidades con statements preparados.
Migraciones, seeding y Prisma Studio
El flujo de trabajo diario con Prisma gira en torno a tres comandos. Los uso a diario:
npx prisma migrate dev --name descripcion: crea una nueva migración SQL desde los cambios de schema.prisma y la aplica.
npx prisma migrate deploy: aplica migraciones pendientes en producción. Es el comando que pones en tu build script de Vercel.
npx prisma studio: abre un GUI en localhost:5555 para explorar y editar datos.
Para seeding, añade este bloque a tu package.json:
Ejecuta con npx prisma db seed. En CI/CD lo encadeno después de migrate deploy para tener entornos de staging con datos consistentes.
Errores comunes al desplegar en Vercel
He tropezado con estos suficientes veces como para tenerlos en un checklist:
"Prisma has detected that this project was built on Vercel, which caches dependencies": añade prisma generate al script build del package.json: "build": "prisma generate && next build". Vercel cachea node_modules entre builds y el cliente generado no.
Migraciones no aplicadas en producción: usa "postinstall": "prisma generate" y un build script que incluya prisma migrate deploy si quieres migraciones automáticas al desplegar. Prefiero desacoplarlo en un job separado para tener control manual.
Variable DATABASE_URL ausente en preview deployments: Vercel separa variables por entorno; recuerda añadirlas a Preview y Production, no solo Development.
Cold start lento: la primera invocación puede tardar 300-800ms mientras se abre la conexión. Con Accelerate o un pooler HTTP el tiempo baja a menos de 50ms porque no hay handshake TCP.
Prisma sigue siendo la opción más productiva por su tooling maduro (Studio, Migrate, tipos generados). Drizzle gana en bundle size y edge nativo sin adapters, pero exige escribir queries más cercanas al SQL. Para equipos pequeños que priorizan velocidad, Prisma; para APIs edge con presupuesto de tamaño ajustado, Drizzle.
¿Cómo hago seed de datos con Prisma en Next.js?
Crea un archivo prisma/seed.ts con las inserciones, referéncialo en el bloque "prisma": { "seed": "tsx prisma/seed.ts" } del package.json y ejecuta npx prisma db seed. Automatízalo en CI ejecutándolo tras prisma migrate deploy.
¿Puedo usar Prisma con SQLite en Vercel?
Técnicamente sí en entornos de desarrollo, pero no en producción serverless: Vercel tiene sistema de archivos efímero y de solo lectura. Para SQLite en producción usa Turso o LibSQL con el adapter Prisma correspondiente, que exponen SQLite sobre HTTP.
¿Prisma funciona con Server Actions?
Sí, y es el patrón recomendado para mutaciones en Next.js 15. Importa tu cliente Prisma dentro de un archivo 'use server', ejecuta la mutación y llama a revalidatePath o revalidateTag para invalidar la caché del Server Component correspondiente.
¿Cuál es el error "Too many connections" y cómo lo evito?
Ocurre cuando cada función serverless abre una conexión nueva a PostgreSQL y saturas el límite (100 por defecto). Se resuelve con un pooler: PgBouncer añadiendo ?pgbouncer=true al DATABASE_URL, Prisma Accelerate, o el driver serverless del proveedor.
Guía práctica sobre las cinco estrategias de renderizado en Next.js 15 con App Router: SSG, ISR, SSR, PPR y CSR. Con código funcional, criterios de decisión y lo que cambia en Next.js 16 con Cache Components.
Aprende a construir APIs con Route Handlers en Next.js 15. Guía práctica con ejemplos de CRUD, CORS, streaming, webhooks, subida de archivos y patrones BFF. Actualizada para Next.js 15 y 16.