Saltar al contenido principal

Prisma ORM v6

Versión estable lanzada en diciembre de 2024. Introduce Driver Adapters estables, el archivo prisma.config.ts y el Query Compiler en preview.

Instalación

Requisitos previos:

  • Node.js 18.x o superior (recomendado 20+)
  • TypeScript 4.7+ (recomendado 5.x)
  • Un proyecto Node.js inicializado (npm init -y)

Instalación de dependencias

npm install @prisma/client@6
npm install -D prisma@6

Inicializar Prisma en el proyecto

npx prisma init

Este comando crea la siguiente estructura:

├── prisma/
│ └── schema.prisma ← Esquema de base de datos
├── .env ← Variables de entorno (DATABASE_URL)

Configuración de la base de datos

Variables de entorno

En el archivo .env generado, se define la URL de conexión:

# PostgreSQL
DATABASE_URL="postgresql://usuario:contraseña@localhost:5432/mi_base_de_datos"

# MySQL
DATABASE_URL="mysql://usuario:contraseña@localhost:3306/mi_base_de_datos"

# SQLite (ideal para desarrollo local)
DATABASE_URL="file:./dev.db"

Configuración del datasource en schema.prisma

datasource db {
provider = "postgresql" // "mysql" | "sqlite" | "sqlserver" | "cockroachdb"
url = env("DATABASE_URL")
}

Archivo prisma.config.ts

En v6 se introduce la posibilidad de usar un archivo de configuración TypeScript centralizado. En v7 será obligatorio, pero en v6 es opcional:

import { defineConfig } from "prisma/config";
import "dotenv/config";

export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
seed: "tsx prisma/seed.ts",
},
});

Creación de modelos

Los modelos en Prisma representan las tablas de la base de datos. Se definen en schema.prisma.

Sintaxis básica de un modelo

model Usuario {
id Int @id @default(autoincrement())
email String @unique
nombre String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

Tipos de datos más comunes

Tipo PrismaEquivalente SQL
StringVARCHAR / TEXT
IntINTEGER
FloatFLOAT / DOUBLE
BooleanBOOLEAN
DateTimeTIMESTAMP
JsonJSON / JSONB
BytesBYTEA / BLOB

Atributos de campo

@id                         // Clave primaria
@default(autoincrement()) // Valor por defecto
@default(now()) // Fecha actual
@unique // Restricción de unicidad
@updatedAt // Actualización automática al modificar
@map("nombre_columna") // Mapear a nombre distinto en BD

Relaciones entre modelos

Relación 1-N:

model Usuario {
id Int @id @default(autoincrement())
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
titulo String
autorId Int
autor Usuario @relation(fields: [autorId], references: [id])
}

Relación N-M:

model Post {
id Int @id @default(autoincrement())
categorias Categoria[]
}

model Categoria {
id Int @id @default(autoincrement())
posts Post[]
}

Relación 1-1:

model Usuario {
id Int @id @default(autoincrement())
perfil Perfil?
}

model Perfil {
id Int @id @default(autoincrement())
bio String
usuarioId Int @unique
usuario Usuario @relation(fields: [usuarioId], references: [id])
}

Migraciones

Crear y aplicar una migración

npx prisma migrate dev --name nombre_migracion

Este comando:

  1. Detecta los cambios en el esquema.
  2. Genera un archivo SQL en prisma/migrations/.
  3. Aplica la migración a la base de datos.
  4. Regenera el Prisma Client.

Otros comandos de migración útiles

# Aplicar migraciones en producción (sin generar nuevas)
npx prisma migrate deploy

# Resetear la base de datos y volver a aplicar todas las migraciones
npx prisma migrate reset

# Inspeccionar el estado de las migraciones
npx prisma migrate status

# Sincronizar el esquema directamente (sin generar migración, útil en dev)
npx prisma db push

Prisma Client — Configuración y uso

Generar el cliente

npx prisma generate

En v6, el cliente se genera en node_modules/@prisma/client por defecto (esto cambia en v7).

Instanciar el cliente

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

Buena práctica: instancia global en desarrollo

Para evitar múltiples instancias en entornos con hot reload (como Next.js):

// lib/prisma.ts
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
globalForPrisma.prisma ?? new PrismaClient({ log: ["query"] });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

Operaciones básicas (CRUD)

Crear registros

Crear un único registro:

const nuevoUsuario = await prisma.usuario.create({
data: {
email: "ana@ejemplo.com",
nombre: "Ana García",
},
});

Crear múltiples registros a la vez:

await prisma.usuario.createMany({
data: [
{ email: "carlos@ejemplo.com", nombre: "Carlos López" },
{ email: "marta@ejemplo.com", nombre: "Marta Ruiz" },
],
skipDuplicates: true, // Ignora duplicados en lugar de lanzar error
});

Leer registros

Buscar por ID (findUnique):

const usuario = await prisma.usuario.findUnique({
where: { id: 1 },
});

Buscar el primero que coincida (findFirst):

const usuario = await prisma.usuario.findFirst({
where: { nombre: { contains: "Ana" } },
});

Obtener todos los registros (findMany):

const usuarios = await prisma.usuario.findMany();

Con filtros, orden y paginación:

const usuarios = await prisma.usuario.findMany({
where: {
nombre: { startsWith: "A" },
},
orderBy: { createdAt: "desc" },
take: 10, // Límite de resultados
skip: 0, // Desplazamiento (offset)
});

Incluir relaciones (eager loading):

const usuarioConPosts = await prisma.usuario.findUnique({
where: { id: 1 },
include: {
posts: true,
},
});

Seleccionar solo ciertos campos:

const usuario = await prisma.usuario.findUnique({
where: { id: 1 },
select: {
id: true,
email: true,
nombre: true,
},
});

Actualizar registros

Actualizar un único registro:

const actualizado = await prisma.usuario.update({
where: { id: 1 },
data: { nombre: "Ana García Martínez" },
});

Actualizar múltiples registros:

await prisma.usuario.updateMany({
where: { nombre: { startsWith: "A" } },
data: { nombre: "Actualizado" },
});

Upsert (crear si no existe, actualizar si existe):

const usuario = await prisma.usuario.upsert({
where: { email: "ana@ejemplo.com" },
update: { nombre: "Ana Actualizada" },
create: {
email: "ana@ejemplo.com",
nombre: "Ana García",
},
});

Eliminar registros

Eliminar un único registro:

await prisma.usuario.delete({
where: { id: 1 },
});

Eliminar múltiples registros:

await prisma.usuario.deleteMany({
where: { createdAt: { lt: new Date("2024-01-01") } },
});

Consultas avanzadas

Filtros compuestos

const usuarios = await prisma.usuario.findMany({
where: {
AND: [
{ nombre: { contains: "García" } },
{ createdAt: { gte: new Date("2024-01-01") } },
],
},
});
// OR: al menos una condición
const usuarios = await prisma.usuario.findMany({
where: {
OR: [
{ email: { endsWith: "@empresa.com" } },
{ nombre: { startsWith: "Admin" } },
],
},
});
// NOT: excluir condición
const usuarios = await prisma.usuario.findMany({
where: {
NOT: { email: { contains: "spam" } },
},
});

Relaciones anidadas (nested writes)

// Crear usuario con posts relacionados en una sola operación
const usuario = await prisma.usuario.create({
data: {
email: "nuevo@ejemplo.com",
nombre: "Nuevo Usuario",
posts: {
create: [
{ titulo: "Mi primer post" },
{ titulo: "Mi segundo post" },
],
},
},
include: { posts: true },
});

Agregaciones

// Contar registros
const total = await prisma.usuario.count();

// Contar con filtro
const activos = await prisma.usuario.count({
where: { activo: true },
});

// Aggregate: mín, máx, suma, promedio
const stats = await prisma.pedido.aggregate({
_avg: { total: true },
_max: { total: true },
_min: { total: true },
_sum: { total: true },
});

// GroupBy
const porCategoria = await prisma.producto.groupBy({
by: ["categoria"],
_count: { id: true },
_avg: { precio: true },
});

Transacciones

Transacción secuencial:

await prisma.$transaction(async (tx) => {
const usuario = await tx.usuario.create({
data: { email: "test@test.com", nombre: "Test" },
});

await tx.post.create({
data: { titulo: "Post inicial", autorId: usuario.id },
});
});

Transacción batch (operaciones independientes que se ejecutan juntas):

const [usuarios, posts] = await prisma.$transaction([
prisma.usuario.findMany(),
prisma.post.findMany(),
]);

Comandos útiles del CLI

npx prisma init              # Inicializar Prisma en el proyecto
npx prisma generate # Generar/actualizar el cliente
npx prisma migrate dev # Crear y aplicar migración en desarrollo
npx prisma migrate deploy # Aplicar migraciones en producción
npx prisma db push # Sincronizar esquema sin migraciones
npx prisma db pull # Generar esquema desde BD existente (introspección)
npx prisma studio # Abrir explorador visual de datos
npx prisma format # Formatear el archivo schema.prisma
npx prisma validate # Validar el archivo schema.prisma