La aplicación funciona en tu máquina, pero al desplegarla en QA o producción algunas consultas fallan con errores como estos:
PrismaClientKnownRequestError:
Invalid `prisma.pedido.findMany()` invocation:
The table `public.Pedido` does not exist in the current database.
code: 'P2021'
The column `Pedido.estado` does not exist in the current database.
code: 'P2022'
Null constraint violation on the {constraint}
code: 'P2011'
En P2011, {constraint} es el marcador del mensaje que figura en la documentación de Prisma; en tu caso verás la restricción afectada. La columna inexistente se reporta como P2022; el mensaje equivalente de PostgreSQL es column "estado" does not exist. A esto se suele sumar que prisma migrate dev detecta una deriva ("drift") y propone reiniciar la base de datos local. Este artículo explica por qué ocurre al mezclar prisma db push con migraciones (Prisma 6, PostgreSQL) y cómo dejar el flujo en orden sin perder datos.
Por qué pasa
Prisma ofrece dos formas de llevar el esquema a una base de datos, y mezclarlas es la raíz de estos síntomas.
prisma db pushno deja rastro. Según la documentación de Prisma, sincroniza el esquema con la base de datos sin generar archivos de migración ni actualizar la tabla_prisma_migrations. Está pensado para prototipar y la propia documentación no lo recomienda para replicar cambios en otros entornos sin perder datos. Si tu CI ejecutaprisma migrate deploy, solo se aplican los archivos deprisma/migrations: lo que hiciste condb pushnunca llega. El resultado es P2021 (tabla inexistente) o P2022 (columna inexistente). P2011 puede aparecer cuando las restricciones de tu base local difieren de las de la historia de migraciones, por ejemplo una columna opcional en local y obligatoria en QA.- La base local se desvía del historial.
migrate devreproduce las migraciones en una base de datos "sombra" para detectar deriva: migraciones editadas o borradas y cambios manuales en la base. Si la encuentra, pide reiniciar la base y la documentación advierte de que eso supone pérdida total de datos. - Editar una migración ya aplicada no la vuelve a ejecutar.
migrate deployaplica solo las migraciones pendientes; la documentación indica que advierte si alguna ya aplicada fue modificada, pero no la repite. Mientras tanto,prisma generatesí lee elschema.prismaactual, así que el cliente consulta una columna que el SQL real nunca creó. De ahí el error 500 concolumn ... does not existjusto después de un despliegue "correcto". La documentación de Prisma lo resume así: nunca debes borrar ni editar una migración a propósito.
Solución
-
Deja de usar
db pushpara cambios que deban llegar a otros entornos. Resérvalo para prototipos desechables. Para cualquier cambio de esquema que vaya a QA o producción, crea una migración. -
Genera la migración sin aplicarla y revisa el SQL:
npx prisma migrate dev --create-only --name agregar_estado_pedidoLa referencia del CLI indica que
--create-onlycrea la migración sin aplicarla. Revisa elmigration.sql, ajústalo si hace falta y aplícalo connpx prisma migrate dev. Si Prisma detecta deriva te ofrecerá reiniciar la base: no aceptes en una base con datos que quieras conservar y resuelve primero la deriva (ver "Variantes"). Si necesitas escribir el SQL a mano, crea la carpetaprisma/migrations/AAAAMMDDHHMMSS_nombre/migration.sql, con el mismo formato de nombre que las demás, y ensáyala como se indica más abajo. -
Nunca edites una migración aplicada: añade otra. Si necesitas una columna que olvidaste, crea una migración nueva:
-- prisma/migrations/20261011130000_agregar_estado_pedido/migration.sql ALTER TABLE "tabla_pedidos" ADD COLUMN "estado" TEXT NOT NULL DEFAULT 'pendiente';Si la tabla ya tiene filas y la columna es
NOT NULL, define un valor por defecto o rellena los datos antes de imponer la restricción; de lo contrario la migración falla. Si ya habías editado una migración aplicada, restaura su contenido original desde el control de versiones y mueve el cambio a la migración nueva. -
Aplica las migraciones con
migrate deployen CI/CD:npx prisma migrate deployEste comando aplica las migraciones pendientes y, según la referencia, no comprueba deriva, no reinicia la base y no usa base sombra. La documentación indica que debe formar parte de un pipeline automatizado y que
migrate devnunca debe usarse en producción. -
Comprueba si hay divergencia entre el historial de migraciones y el esquema:
npx prisma migrate diff \ --from-migrations prisma/migrations \ --to-schema-datamodel prisma/schema.prisma \ --shadow-database-url "$SHADOW_DATABASE_URL" \ --exit-codeCon
--from-migrations,migrate diffnecesita una base sombra: usa una base vacía y desechable, nunca la real. Con--exit-codeel comando termina en 0 si no hay diferencias y en 2 si las hay. Los nombres de las opciones cambian entre versiones de Prisma (las ediciones recientes de la documentación usan--from-schemay--to-schema, y Prisma 7 eliminó--shadow-database-url); ejecutanpx prisma migrate diff --helppara ver los de tu versión. -
Captura el detalle del error. En el manejador de errores registra el código y
meta, que según la documentación contiene información adicional sobre el error:import { Prisma } from '@prisma/client'; try { await prisma.pedido.findMany(); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError) { console.error(e.code, e.meta); } throw e; }
Cómo verificar que quedó resuelto
- Ejecuta el estado de migraciones contra cada entorno, cambiando
DATABASE_URL:
La referencia indica que el comando termina con código 1 si hay migraciones sin aplicar, historial divergente o migraciones fallidas. Un código 0 en local, QA y producción es la señal buscada.npx prisma migrate status - Compara los nombres aplicados entre entornos. Deben ser la misma lista:
SELECT migration_name FROM _prisma_migrations ORDER BY migration_name; - Compara una copia de la base de producción (nunca la base real) con tu esquema. En Prisma 6 la opción
--from-urlacepta la conexión a esa copia:
Debe terminar con código 0, sin diferencias. Un código 2 indica que la copia carece de algo que el esquema espera, justo el síntoma de este artículo.npx prisma migrate diff \ --from-url "$COPIA_PRODUCCION_URL" \ --to-schema-datamodel prisma/schema.prisma \ --exit-code - Ensaya el despliegue en un PostgreSQL desechable antes de tocar producción. Restaura allí una copia de los datos con
pg_restorey ejecuta:
Las migraciones pendientes deben aplicarse sin errores. Detén el contenedor condocker run --rm -d --name pg-ensayo -e POSTGRES_PASSWORD=ensayo -p 5433:5432 postgres:16 DATABASE_URL="postgresql://postgres:ensayo@localhost:5433/postgres" npx prisma migrate deploydocker stop pg-ensayo.
Variantes y errores relacionados
migrate dev propone reiniciar la base por deriva
La documentación de Prisma ofrece dos salidas solo para desarrollo. Si puedes descartar los cambios manuales, usa npx prisma migrate reset y luego migrate dev. Si quieres conservarlos, ejecuta npx prisma db pull y después npx prisma migrate dev --name cambio_introspectado. Ninguna de las dos es para producción.
Una migración falló a medias
Para migraciones fallidas, prisma migrate resolve --rolled-back <nombre> la marca como revertida para poder volver a aplicarla, y --applied <nombre> la marca como aplicada si terminaste sus pasos a mano. La referencia indica que el comando solo funciona sobre migraciones fallidas. Antes de resolverla, revisa la columna logs de _prisma_migrations, donde queda el detalle del fallo.
db push y pérdida de datos
Si un cambio puede perder datos, db push falla salvo que añadas --accept-data-loss. Esa opción no resuelve el problema de fondo: el cambio seguirá sin migración.
MongoDB
En MongoDB el flujo previsto es db push, porque migrate no se usa allí. Todo lo anterior aplica a bases relacionales.
Prisma 7 y posteriores
Este artículo describe Prisma 6. Las versiones más recientes cambian varios comandos y opciones, por lo que conviene consultar la documentación de la versión instalada.
Resumen
db pushsincroniza la base local pero no crea migraciones, así que QA y producción nunca reciben esos cambios (P2021, P2022, P2011).- Todo cambio que deba llegar a otros entornos se escribe como migración:
migrate dev --create-only, revisión del SQL y commit. - Una migración ya aplicada no se edita: se añade una nueva con
ALTER TABLE. - En CI/CD se usa
migrate deploy, que no evalúa deriva ni reinicia la base;migrate deves solo para desarrollo. - Verifica con
migrate status, conmigrate diff --exit-codey con un ensayo en una base desechable.
Comentarios
Publicar un comentario