Saltar al contenido principal
Principiante PrismaBackendNode.js

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.

Fran Cobos 5 min de lectura 862 palabras

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
  • .env con DATABASE_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.

Fran Cobos

Fran Cobos

Desarrollador Full Stack especializado en IA aplicada, automatización y desarrollo web. Escribo sobre herramientas, tutoriales y casos reales para programadores.

¿Necesitas desarrollo a medida?

Apps web, IA, módulos ERP — cuéntame tu proyecto.