Prisma desde Cero: Tutorial Completo en Español 2026 (Schema, Migrate, Queries)
Aprende Prisma ORM desde cero: instalar, definir el schema, migraciones, queries CRUD, relaciones y patrones avanzados. El tutorial en español más completo de 2026.
Tabla de contenidos
Prisma es el ORM más usado en el ecosistema Node.js/TypeScript en 2026 y con razón: el tipado automático desde el schema elimina toda una categoría de bugs que otros ORMs no previenen.
Instalación
# Crear proyecto nuevo o ir a uno existente
npm init -y
npm install typescript ts-node @types/node --save-dev
npm install @prisma/client
npm install prisma --save-dev
# Inicializar Prisma
npx prisma init --datasource-provider postgresql
Esto crea:
prisma/schema.prisma— define tus modelos.envconDATABASE_URL
Configurar la base de datos
# .env
DATABASE_URL="postgresql://usuario:contraseña@localhost:5432/mi_app_db"
# Para desarrollo con SQLite (sin instalar nada)
# DATABASE_URL="file:./dev.db"
Definir el schema
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
nombre String
plan String @default("free")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relaciones
posts Post[]
profile Profile?
}
model Profile {
id String @id @default(cuid())
bio String?
avatar String?
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Post {
id String @id @default(cuid())
titulo String
contenido String?
publicado Boolean @default(false)
autorId String
autor User @relation(fields: [autorId], references: [id])
tags Tag[]
createdAt DateTime @default(now())
}
model Tag {
id String @id @default(cuid())
nombre String @unique
posts Post[]
}
Migraciones
# Crear y aplicar migración (genera SQL)
npx prisma migrate dev --name crear_tablas_iniciales
# Ver el SQL que generó
cat prisma/migrations/*/migration.sql
# Aplicar migraciones en producción
npx prisma migrate deploy
# Reset completo (dev only) — borra todos los datos
npx prisma migrate reset
Generar el cliente TypeScript
npx prisma generate
Ejecuta esto después de cada cambio en el schema. El cliente generado incluye los tipos de todos tus modelos.
Queries CRUD
Configurar el cliente (singleton)
// lib/prisma.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ?? new PrismaClient({ log: ['error'] });
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Create
import { prisma } from './lib/prisma';
// Crear usuario
const usuario = await prisma.user.create({
data: {
email: 'fran@ejemplo.com',
nombre: 'Fran',
},
});
// Crear con relación anidada
const usuarioConProfile = await prisma.user.create({
data: {
email: 'ana@ejemplo.com',
nombre: 'Ana',
profile: {
create: {
bio: 'Desarrolladora frontend',
avatar: 'https://ejemplo.com/avatar.jpg',
},
},
},
include: { profile: true }, // incluye el profile en la respuesta
});
Read
// Buscar por id
const user = await prisma.user.findUnique({
where: { id: '...' },
});
// Buscar con condiciones
const usersPro = await prisma.user.findMany({
where: {
plan: 'pro',
createdAt: {
gte: new Date('2026-01-01'), // mayor o igual que
},
},
orderBy: { createdAt: 'desc' },
take: 10, // LIMIT
skip: 0, // OFFSET
});
// Incluir relaciones
const postConAutor = await prisma.post.findUnique({
where: { id: '...' },
include: {
autor: {
select: { nombre: true, email: true }, // select solo lo que necesitas
},
tags: true,
},
});
// Select específico (más eficiente que include completo)
const emails = await prisma.user.findMany({
select: { email: true, nombre: true },
});
Update
// Actualizar uno
const actualizado = await prisma.user.update({
where: { id: '...' },
data: { plan: 'pro' },
});
// Upsert — crea si no existe, actualiza si existe
const usuario = await prisma.user.upsert({
where: { email: 'fran@ejemplo.com' },
create: {
email: 'fran@ejemplo.com',
nombre: 'Fran',
},
update: {
nombre: 'Fran Actualizado',
},
});
// Actualizar muchos
await prisma.user.updateMany({
where: { plan: 'trial' },
data: { plan: 'free' },
});
Delete
// Borrar uno
await prisma.user.delete({
where: { id: '...' },
});
// Borrar muchos
await prisma.user.deleteMany({
where: {
createdAt: { lt: new Date('2025-01-01') },
plan: 'free',
},
});
Transacciones
// Transacción — si algo falla, todo se revierte
const resultado = await prisma.$transaction(async (tx) => {
const usuario = await tx.user.create({
data: { email: 'nuevo@ejemplo.com', nombre: 'Nuevo' },
});
const post = await tx.post.create({
data: {
titulo: 'Mi primer post',
autorId: usuario.id,
},
});
return { usuario, post };
});
Paginación
async function getPaginatedPosts(page: number, perPage = 10) {
const [posts, total] = await prisma.$transaction([
prisma.post.findMany({
where: { publicado: true },
orderBy: { createdAt: 'desc' },
skip: (page - 1) * perPage,
take: perPage,
}),
prisma.post.count({ where: { publicado: true } }),
]);
return {
posts,
totalPages: Math.ceil(total / perPage),
currentPage: page,
};
}
Prisma Studio: UI para tu base de datos
npx prisma studio
Abre una interfaz web en localhost:5555 para ver y editar los datos sin escribir SQL.
Consejos para producción
# Genera el cliente antes de iniciar la app
{
"scripts": {
"postinstall": "prisma generate",
"build": "prisma generate && tsc",
"start": "prisma migrate deploy && node dist/index.js"
}
}
Si tu proyecto usa TypeScript, las queries de Prisma te darán autocompletado completo. Combina esto con la guía de TypeScript para developers JavaScript para aprovechar todo el tipado.
Para elegir la base de datos que usarás con Prisma, la comparativa de PostgreSQL vs MySQL te ayuda a decidir.