Prisma sin Prisma Client: consultas de GraphQL seguras desde el punto de vista tipológico en Next.js
Aprenda cómo utilizar Prisma para el trabajo con esquemas, generar tipos Kysely con prisma-kysely, elegir un dialecto Neon o pg, y realizar consultas de forma segura desde el código del servidor de Next.js.
Fuentes: **Using Prisma for Schema and Kysely for Queries in a Next.js App**
Prisma es excelente para el diseño de esquemas, pero Prisma Client representa una dependencia considerable que hay que incluir en cada función serverless cuando lo único que se desea es SQL seguro desde el punto de vista tipológico. Una división práctica sería: Prisma gestiona el esquema durante el desarrollo, un generador lo convierte en tipos de TypeScript, y Kysely ejecuta las consultas en producción. Esta guía muestra cómo configurarlo en un proyecto Next.js App Router y compara el dialecto HTTP de Neon con un pool clásico de pg.
Si prefiere el enfoque convencional con Prisma Client en tiempo de ejecución, consulte cómo configurar Prisma 7 en un proyecto Next.js 16.
Cómo se dividen las responsabilidades
Cada herramienta en esta configuración tiene una tarea clara:
- Prisma se encarga del diseño de la base de datos: el archivo de esquema, la sincronización o migración de la base de datos, y herramientas como Prisma Studio para explorar los datos.
- Kysely es el generador de consultas en tiempo de ejecución. Escribes consultas con formato SQL en TypeScript; el compilador verifica los nombres de las tablas y columnas, y la propia biblioteca es pequeña.
- prisma-kysely actúa como vínculo: es un generador de Prisma que emite definiciones de tipo Kysely directamente a partir de tu esquema Prisma.
Prisma permanece dentro de tu flujo de trabajo como desarrollador, mientras que Kysely es la única capa de base de datos en el código desplegado. El compromiso: pierdes la API de Prisma Client que tiene en cuenta las relaciones, como los include anidados y las escrituras anidadas, así como la posibilidad de realizar uniones de escritura por tu cuenta. Si aún estás eligiendo una capa de datos en general, la comparación entre SQL bruto, Prisma y Drizzle aborda la decisión de forma más amplia.
Instalación de los paquetes
El entorno en tiempo de ejecución necesita Kysely además de un dialecto y un controlador; esto instala la pila basada en Neon (pnpm aquí, pero también funcionan npm o yarn):
pnpm add kysely kysely-neon @neondatabase/serverless
pnpm add -D prisma prisma-kysely
Ten en cuenta que prisma y prisma-kysely son dependencias de desarrollo: solo gestionan el esquema y generan código.
Definición del esquema y generación de tipos Kysely
El esquema es un Prisma normal, con la diferencia de que el generador es prisma-kysely (que escribe en ./types) en lugar del generador de cliente habitual. Define User y Post con una relación uno-a-muchos.
// db/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator kysely {
provider = "prisma-kysely"
output = "./types"
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
authorId Int
createdAt DateTime @default(now())
author User @relation(fields: [authorId], references: [id])
}
prisma generate ahora genera tipos Kysely en lugar de un cliente, y prisma db push aplica el esquema a la base de datos:
pnpm prisma generate
pnpm prisma db push
El resultado es un archivo como db/types/kysely.d.ts que contiene una interfaz DB que describe cada tabla. Tres consideraciones importantes:
- El esquema se encuentra en
db/schema.prisma, no en elprisma/schema.prismapredeterminado de Prisma, por lo que hay que indicarle a la CLI su ubicación (por ejemplo con--schema) según lo exija la versión de Prisma.
db push sincroniza la base de datos sin registrar archivos de migración. Para datos de producción, prisma migrate dev y prisma migrate deploy generan migraciones versionadas manteniendo el resto del flujo de trabajo sin cambios.url, consulte la documentación actual.Escripciones de paquete para el ciclo diario
Algunas scripts hacen que el flujo de trabajo sea evidente para el equipo:
{
"scripts": {
"db:push": "prisma db push",
"db:generate": "prisma generate",
"db:studio": "prisma studio"
}
}
Con estos en su lugar, un cambio de esquema se reduce a dos comandos:
# To generate the types
pnpm db:generate
# To push to the remote DB
pnpm db:push
La base de datos y los tipos de Kysely permanecen alineados, por lo que el compilador marca cualquier consulta que utilice una columna renombrada o eliminada.
Elegir un dialecto de Kysely
Kysely no habla directamente con la base de datos. Un dialecto se interponga entre el generador de consultas y el controlador, y sabe cómo compilar y enviar consultas para una base de datos y un método de conexión específicos. Los dialectos oficiales abarcan PostgreSQL, MySQL y SQLite; los comunitarios cubren servicios como Neon, PlanetScale y Turso. Para Postgres, existen dos opciones que sirven para la mayoría de los casos.
Neon over HTTP para despliegues serverless
En Vercel o una plataforma similar, el controlador HTTP de Neon encaja perfectamente: cada consulta es una solicitud sin estado, por lo que no hay conexión persistente que mantener entre invocaciones breves. La configuración envuelve a neon() dentro de NeonDialect y tipa a Kysely con el DB generado:
// db/index.ts
import { Kysely } from 'kysely'
import { NeonDialect } from 'kysely-neon'
import { neon } from '@neondatabase/serverless'
import type { DB } from './types/kysely'
const db = new Kysely<DB>({
dialect: new NeonDialect({
neon: neon(process.env.DATABASE_URL!),
}),
})
export default db
El ! solo silencia a TypeScript; no valida nada. La limitación más grande es que kysely-neon a través de HTTP no puede ejecutar transacciones ni consultas basadas en sesiones, por lo que es adecuado para operaciones simples de CRUD y páginas con mucho tráfico de lectura, en lugar de tareas que requieren múltiples instrucciones. Con el controlador WebSocket de Neon no necesitas kysely-neon en absoluto: pasa el Pool de Neon al PostgresDialect integrado en Kysely. La API de kysely-neon también ha cambiado entre versiones, así que compárala con su README actual.
node-postgres para servidores de larga duración
Para un servidor Node.js que funcione durante mucho tiempo, el controlador oficial pg es la opción más completa, ya que incluye transacciones, gestión de pools y sentencias preparadas. Se integra con el propio PostgresDialect de Kysely:
// db/index.ts
import { Kysely, PostgresDialect } from 'kysely'
import { Pool } from 'pg'
import type { DB } from './types/kysely'
const db = new Kysely<DB>({
dialect: new PostgresDialect({
pool: new Pool({
connectionString: process.env.DATABASE_URL,
}),
}),
})
export default db
Elegir entre ellos
La diferencia radica en el modelo de conexión. kysely-neon es HTTP sin estado: ligero y adecuado para entornos serverless, pero no permite transacciones. pg mantiene abiertas conexiones TCP en grupo, con todo el conjunto de funciones disponibles, lo que es adecuado para servidores que permanecen activos continuamente. Utilice kysely-neon en plataformas serverless como Vercel o Netlify, y pg o el grupo de WebSocket de Neon cuando necesite realizar transacciones. Tenga cuidado con los grupos pg dentro de funciones serverless: cada instancia abre sus propias conexiones y puede agotar el límite del banco de datos sin un gestor externo de conexiones.
Consultas desde un componente del servidor
Cualquier código del lado del servidor puede importar db. Este componente del servidor muestra una lista de usuarios, seleccionando tres columnas ordenadas por id:
// app/users/page.tsx
import db from '@/db'
export default async function UsersPage() {
const users = await db
.selectFrom('user')
.select(['id', 'name', 'email'])
.orderBy('id')
.execute()
return (
<div>
<h1>Users</h1>
<ul>
{users.map(u => (
<li key={u.id}>{u.name} ({u.email})</li>
))}
</ul>
</div>
)
}
Dado que DB proviene del esquema de Prisma, si un nombre de tabla o columna está escrito incorrectamente se falla la verificación de tipos, y users se infiere con exactamente los campos seleccionados.
Un problema: Prisma nombra las tablas según los modelos por defecto, por lo que este esquema crea una tabla User, y los tipos generados utilizan ese nombre. selectFrom('user') solo realiza la verificación de tipos si se agrega @@map("user") al modelo; de lo contrario, la consulta utiliza 'User'. También hay que mantener db fuera de los Componentes Cliente, ya que accede a un secreto exclusivo del servidor.
El flujo de trabajo diario
Una vez que todo está configurado, el bucle se ve así:
- Modificar los modelos en
db/schema.prisma. - Volver a generar los tipos y aplicar los cambios con los dos scripts.
- Utilizar
dbdesde Componentes Servidor, controladores de rutas o Acciones Servidor.
El layout resultante mantiene todo lo relacionado con la base de datos bajo db/:
📦 my-next-app
├── 📁 app
│ └── 📁 users
│ └── page.tsx
├── 📁 db
│ ├── schema.prisma
│ ├── index.ts
│ └── 📁 types
│ └── kysely.d.ts
├── 📁 node_modules
├── .env
├── package.json
├── pnpm-lock.yaml
└── tsconfig.json
Conclusión
Esta separación permite mantener el flujo de trabajo del esquema de Prisma y Studio sin incluir Prisma Client, y ofrece una capa de consultas similar a SQL cuyos tipos siguen el esquema.
- Mantenga
prismayprisma-kyselycomo dependencias de desarrollo; solo Kysely, un dialecto y un driver se envían a producción. - Use el dialecto Neon HTTP para cargas de trabajo serverless simples, y cámbiese a un
PostgresDialectcon conexión compartida cuando necesite transacciones. - Tenga cuidado con la denominación de las tablas: los tipos generados siguen los nombres de la base de datos, que por defecto son los nombres de los modelos de Prisma.
db push a migraciones adecuadas antes de que los datos en la base de datos comiencen a ser importantes.Lecturas relacionadas
- Generar automáticamente un cliente API type-safe de Next.js a partir de NestJS Swagger — Aprenda cómo eliminar tipos API duplicados utilizando NestJS Swagger y Orval para generar automáticamente ganchos React Query type-safe para Next.js.
- Configuración de Prisma 7 en un proyecto Next.js 16 con TypeScript — Aprenda cómo instalar, configurar y migrar a Prisma 7 con PostgreSQL en una aplicación Next.js 16, y luego crear un cliente singleton para evitar fugas de conexiones.