Fundamentos de Migraciones
7 ejemplos para los fundamentos de la migración de esquemas: 5 básicos y 2 intermedios. SQL versionado en git es la única fuente de verdad de cómo se ve la producción.
Prerrequisitos
mkdir -p db/migrations
git init # las migraciones viven junto al código de la aplicación- Una tabla de historial ordenada (
flyway_schema_history,liquibase.databasechangelog, o personalizada). - Nunca apliques DDL editado a mano en producción sin el mismo SQL en un archivo de migración fusionado.
Ejemplos Básicos
1. Primer Archivo de Migración
-- db/migrations/V001__init_schema.sql
CREATE SCHEMA app AUTHORIZATION app_owner;
CREATE TABLE app.users (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email text NOT NULL UNIQUE,
created_at timestamptz NOT NULL DEFAULT now()
);- El nombre del archivo lleva el orden (
V001, prefijo de timestamp, o convención de la herramienta). - Los patrones idempotentes (
IF NOT EXISTS) son específicos de la herramienta; las migraciones versionadas de Flyway no se vuelven a ejecutar. - Revisa las migraciones como código de aplicación en las PRs.
2. Tabla de Historial de Esquema
CREATE TABLE IF NOT EXISTS app.schema_migrations (
version text PRIMARY KEY,
applied_at timestamptz NOT NULL DEFAULT now(),
checksum text
);- El ejecutor registra las versiones aplicadas después del éxito.
- El checksum detecta la manipulación de archivos ya aplicados.
- Nunca elimines filas del historial para "arreglar" un despliegue; soluciona hacia adelante con una nueva migración.
Relacionado: Flyway y Liquibase - ejecutores empresariales
3. Rol de Migración Separado
CREATE ROLE app_owner NOLOGIN;
CREATE ROLE app_migrator LOGIN PASSWORD 'vault';
GRANT app_owner TO app_migrator;
-- Sesión de migración
SET ROLE app_owner;
CREATE TABLE app.orders (id bigint PRIMARY KEY);
RESET ROLE;- El rol de tiempo de ejecución
app_apino debe poseer tablas ni tener derechos DDL. - La CI de migración utiliza el mismo rol que el despliegue de producción para concesiones idénticas.
- Las líneas
SET ROLEpertenecen al wrapper de migración o a la inicialización de la conexión solo para el migrador.
4. DDL Transaccional (Cuando es Seguro)
BEGIN;
CREATE TABLE app.feature_flags (
key text PRIMARY KEY,
enabled boolean NOT NULL DEFAULT false
);
INSERT INTO app.feature_flags (key) VALUES ('new_checkout');
COMMIT;- La mayoría de los DDL en PostgreSQL son transaccionales; una migración fallida se revierte.
- Excepciones:
CREATE INDEX CONCURRENTLY,DROP INDEX CONCURRENTLY,VACUUM- no se pueden ejecutar dentro de un bloque de transacción. - Divide las sentencias inseguras en archivos de migración separados con notas operacionales.
5. Concesión en la Misma Migración
CREATE TABLE app.products (id bigint PRIMARY KEY, sku text NOT NULL);
GRANT SELECT ON app.products TO app_readers;
GRANT SELECT, INSERT, UPDATE, DELETE ON app.products TO app_writers;- O confía en
ALTER DEFAULT PRIVILEGESde la migración de arranque. - Las concesiones faltantes causan éxito en el despliegue pero errores de permisos en tiempo de ejecución.
- Prueba la migración contra una base de datos nueva en CI, no solo contra portátiles de desarrollo.
Ejemplos Intermedios
6. Vista Previa de Expandir/Contraer
-- Expandir: añadir columna nullable (despliegue seguro)
ALTER TABLE app.orders ADD COLUMN discount_cents integer;
-- La v2 de la aplicación escribe la columna; un trabajo de relleno completa los valores
-- Contraer (migración posterior): forzar NOT NULL después del relleno
ALTER TABLE app.orders ALTER COLUMN discount_cents SET NOT NULL;- Envía cambios aditivos antes que los destructivos.
- Despliegue en dos fases: expansión del esquema, despliegue de la aplicación, relleno de datos, contracción del esquema.
- Nunca elimines una columna hasta que ningún código la lea.
Relacionado: Patrón Expandir/Contraer - flujo completo
7. Aplicar en CI en Base de Datos Efímera
# extracto del pipeline
services:
postgres:
image: postgres:18.4
steps:
- run: flyway migrate -url=jdbc:postgresql://postgres:5432/test
- run: psql $TEST_URL -f ci/assert_schema.sql- Cada PR aplica la cadena completa de migraciones a una base de datos vacía.
- Detecta errores de orden y concesiones faltantes antes de la fusión.
- Empareja la versión principal de PostgreSQL en CI con la versión principal de destino de producción.
Versiones del Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, y PostGIS 3.5+.