Objetivos de aprendizaje
Después de leer este artículo podrás:
- Ejecutar migraciones de Prisma, Drizzle o Alembic como paso del deploy
- Escribir cambios de esquema que no bloqueen una tabla con mucho tráfico
- Comprobar que una migración se aplicó y recuperarte cuando falla
En esta página
- ¿Qué necesitas antes de empezar?
- ¿Cuál es el orden correcto de un deploy con migraciones?
- ¿Cómo se ejecutan migraciones con Prisma?
- ¿Cómo se ejecutan migraciones con Drizzle?
- ¿Cómo se ejecutan migraciones con Alembic?
- ¿Cómo se escribe una migración que no bloquee la tabla?
- ¿Cómo sabes si la migración funcionó, y qué hacer si falló?
- Cómo hacerlo en Square Cloud
- Preguntas frecuentes
Una migración es un archivo versionado que cambia el esquema de tu base de datos: crear una tabla, añadir una columna, crear un índice. La herramienta registra qué archivos ya se ejecutaron, así que todos los entornos terminan con el mismo esquema. Lo difícil no es escribir el archivo. Es ejecutarlo en el momento correcto del deploy, una sola vez, con un camino de vuelta.
Esta guía cubre las tres configuraciones más comunes (Prisma, Drizzle y Alembic), el orden de los pasos y cómo escribir cambios que no congelen una tabla con mucho tráfico. Si tu versión de la herramienta es distinta, revisa los comandos en su documentación oficial.
¿Qué necesitas antes de empezar?#
- Acceso a la base de datos desde donde corre el deploy, con la cadena de conexión en una variable de entorno como
DATABASE_URL. Consulta qué son las variables de entorno. - Archivos de migración en tu repositorio, generados por tu herramienta y versionados junto con el código.
- Una copia de los datos que puedas restaurar. Si no tienes una reciente, lee primero cómo hacer una copia de seguridad de una base de datos.
¿Cuál es el orden correcto de un deploy con migraciones?#
Cuatro pasos, en este orden:
- Guarda un punto de restauración. Un dump o un snapshot de la base de datos hecho por la plataforma.
- Aplica las migraciones. Un proceso, una vez, con el comando de deploy de la herramienta.
- Comprueba el resultado. El código de salida del comando debe ser 0, y la herramienta debe indicar que el esquema está al día.
- Arranca el código nuevo. Solo después de que el paso 3 haya salido bien.
El paso 4 depende del paso 3. Si la migración falla y la aplicación arranca igual, el código consulta columnas que no existen. Encadenar los comandos con && garantiza ese orden sin esfuerzo, porque el segundo comando no se ejecuta cuando el primero falla.
Ten cuidado con varias instancias de la aplicación. Si dos arrancan a la vez y ambas ejecutan la migración, pueden chocar. Ejecuta la migración desde un único lugar (un job de CI o una instancia), no desde cada réplica.
¿Cómo se ejecutan migraciones con Prisma?#
En producción se usa prisma migrate deploy, que aplica los archivos de migración que ya están en tu repositorio. La documentación de Prisma indica ejecutarlo como parte del pipeline de CI/CD y desaconseja lanzarlo desde tu máquina contra una base de datos de producción. En cambio, prisma migrate dev es un comando de desarrollo, y la documentación dice que nunca debe usarse en producción. La CLI prisma suele ser una dependencia de desarrollo, así que debe estar instalada donde se ejecuta el comando.
{
"scripts": {
"migrate": "prisma migrate deploy",
"start": "npm run migrate && node dist/index.js"
}
}En local creas la migración con npx prisma migrate dev --name add_orders_table, haces commit de la carpeta generada en prisma/migrations y dejas que el deploy la aplique.
¿Cómo se ejecutan migraciones con Drizzle?#
Drizzle divide el trabajo en dos. drizzle-kit generate escribe archivos SQL a partir de tu esquema, y drizzle-kit migrate aplica los que aún no se aplicaron. Necesita el dialect y las credenciales de conexión, en drizzle.config.ts o con las flags --dialect y --url. Las migraciones aplicadas quedan registradas en una tabla __drizzle_migrations, en el esquema drizzle por defecto.
{
"scripts": {
"generate": "drizzle-kit generate",
"migrate": "drizzle-kit migrate",
"start": "npm run migrate && node dist/index.js"
}
}drizzle-kit suele ser una dependencia de desarrollo, así que debe estar instalado donde se ejecuta el comando. Para no depender de él, el paquete drizzle-orm incluye un migrator que puedes llamar desde el código antes de que arranque el servidor:
import { drizzle } from "drizzle-orm/node-postgres";
import { migrate } from "drizzle-orm/node-postgres/migrator";
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
await migrate(drizzle(pool), { migrationsFolder: "./drizzle" });
await pool.end();¿Cómo se ejecutan migraciones con Alembic?#
Alembic es la herramienta de migraciones de SQLAlchemy en Python. Creas el entorno una vez con alembic init alembic, creas una revisión con alembic revision -m "create account table" y aplicas todo con alembic upgrade head.
alembic upgrade head && python main.pyOtros dos comandos ayudan en un deploy. alembic current muestra la revisión en la que está la base de datos, y head solo aparece cuando coincide con la última revisión de tu código. alembic downgrade -1 retrocede una revisión. Deja la URL de la base de datos fuera de alembic.ini: lee DATABASE_URL del entorno en env.py para que ninguna contraseña acabe en Git.
¿Cómo se escribe una migración que no bloquee la tabla?#
La mayoría de los cambios de esquema toman un bloqueo sobre la tabla, y las consultas de tu aplicación esperan mientras se mantiene. En PostgreSQL, ALTER TABLE toma un bloqueo ACCESS EXCLUSIVE, que impide lecturas y escrituras, salvo en las formas en que la documentación indica otro bloqueo. En una tabla pequeña dura milisegundos. En una grande, un recorrido dentro del bloqueo puede congelar la aplicación. Algunos hábitos ayudan:
- Añade columnas con un default constante. Para un
DEFAULTno volátil, PostgreSQL guarda el valor en los metadatos de la tabla en lugar de reescribir cada fila, así que la sentencia es rápida incluso en tablas grandes. - Divide el
NOT NULL.SET NOT NULLrecorre toda la tabla. Añade una restricciónCHECK (col IS NOT NULL)comoNOT VALID, valídala aparte y después aplicaNOT NULL: PostgreSQL se salta el recorrido cuando un check válido ya demuestra que no hay nulos. - Añade claves foráneas como
NOT VALID.ADD FOREIGN KEY ... NOT VALIDse salta el recorrido largo, yVALIDATE CONSTRAINTdespués solo toma un bloqueoSHARE UPDATE EXCLUSIVE. - No renombres ni elimines en el mismo deploy que el cambio de código. El código antiguo que sigue corriendo (o un rollback) se rompería. Añade la columna nueva, publica el código que la usa y elimina la antigua en un deploy posterior.
- Saca las correcciones grandes de datos de la migración. Actualizar millones de filas en una sola sentencia mantiene bloqueos y llena el log. Haz el backfill por lotes desde un script.
¿Cómo sabes si la migración funcionó, y qué hacer si falló?#
Comprueba tres cosas después del comando: el código de salida, el estado de la propia herramienta (alembic current o prisma migrate status) y el esquema en sí (\d nombre_tabla en psql). Después lee los logs de la aplicación cuando arranque. Consulta cómo leer los logs de tu aplicación.
Cuando una migración falla, detén el deploy y lee el error. En PostgreSQL, el DDL corre dentro de una transacción, así que el cambio suele revertirse, y corriges el archivo y lo ejecutas de nuevo. MySQL confirma la mayoría de los cambios de esquema de forma implícita, así que un fallo puede dejar un cambio aplicado a medias que corriges a mano. En ambos casos, el punto de restauración del paso 1 es tu salida. Más sobre volver atrás en rollbacks y deploys sin downtime.
Errores comunes:
- Editar una migración que ya se ejecutó en producción. Crea una nueva.
- Ejecutar
migrate devo--autogeneratea ciegas en producción. Lee antes el SQL generado. - Dejar que cada réplica ejecute la migración al arrancar.
- Poner la cadena de conexión en el repositorio en lugar de en una variable de entorno.
Cómo hacerlo en Square Cloud#
Square Cloud ofrece hosting de PostgreSQL y MySQL (además de MongoDB y Redis) a partir del plan Standard, en el mismo datacenter que tus aplicaciones. El panel te da la URL de conexión completa y un certificado para descargar; TLS es obligatorio, así que el driver debe confiar en la CA descargada (y, en PostgreSQL, también presentar el certificado .pem).
Guarda la URL de conexión como variable de entorno de la aplicación, desde el panel, la API, la CLI o VS Code. El cambio se aplica en el siguiente reinicio, sin rebuild. Después elige dónde se ejecuta la migración:
- Al arrancar. El comando de inicio se ejecuta como comando de shell, así que
npm run migrate && npm startfunciona, igual que la llamadamigrate()de Drizzle desde el código. No hay etapa de build, y las dependencias se instalan al arrancar conNODE_ENV=production, así que las devDependencies no se instalan: dejaprismaodrizzle-kitendependenciesy generadist/en CI o dentro del comando de inicio. - Desde tu máquina o desde CI. La base de datos acepta conexiones desde fuera con su host, puerto, contraseña y certificado, así que un job de CI puede migrarla antes de que hagas el deploy con GitHub Actions.
Si varias aplicaciones comparten la base de datos, ejecuta la migración desde un solo lugar. Para el punto de restauración, haz un snapshot manual antes del deploy. Los snapshots manuales existen en todos los planes, y un snapshot de base de datos se puede restaurar en la misma base, en otra del mismo motor o en una base nueva, así que puedes probar antes una migración arriesgada en una copia. Todo plan que incluye bases de datos tiene también un snapshot automático diario, que se guarda 7 días.
Consulta la página de hosting de bases de datos para ver planes y motores.
Hosting de bases de datos
MongoDB, PostgreSQL, MySQL y Redis junto a tu app
Preguntas frecuentes
¿Las migraciones deben ejecutarse automáticamente en cada deploy?
Para una sola instancia de la aplicación, sí: así el código y el esquema van a la par. Ejecútala una vez por deploy, como paso propio, y haz que el deploy se detenga si la migración falla.
¿Qué pasa si una migración falla a medias?
Depende de la base de datos. PostgreSQL puede revertir DDL dentro de una transacción, así que una migración fallida no suele dejar rastro. MySQL confirma la mayoría de los cambios de esquema de forma implícita, así que un fallo puede dejar un cambio parcial que corriges a mano.
¿Es seguro ejecutar prisma migrate dev en producción?
No. Prisma documenta migrate dev como un comando de desarrollo que nunca debe usarse en producción. En producción se usa prisma migrate deploy, que solo aplica migraciones que ya existen.
¿Cómo deshago una migración?
Alembic puede ejecutar pasos de downgrade, pero la mayoría de los equipos prefiere una nueva migración hacia adelante que revierta el cambio. Restaurar un snapshot hecho antes del deploy es la red de seguridad para los datos.
Más en Bases de datos
Ver los 24 artículos- ¿Cuánto cuesta una base de datos en la nube?Una base de datos en la nube cuesta desde cero hasta cientos de dólares al mes. Qué define el precio: instancia, disco, tráfico, snapshots y cómo estimar el tuyo.
- Cómo hospedar una base de datos en la nubePara hospedar una base de datos, elige el motor, crea la instancia, guarda la cadena de conexión en una variable de entorno y prueba la conexión. Guía paso a paso.
- Qué es Redis y para qué sirveRedis es una base de datos en memoria que guarda pares clave-valor y estructuras de datos. Mira cómo funciona, para qué sirve y cuándo no usarlo.
- Cómo hacer un respaldo de tu base de datosRespalda MySQL, PostgreSQL y MongoDB con mysqldump, pg_dump y mongodump, y restaura el dump. Mira los comandos, cómo verificar y los errores comunes.