El sistema de migración de D1 fue diseñado para la simplicidad, no para la seguridad. Archivos .sql numerados en secuencia, aplicados mediante wrangler d1 migrations apply, sin reversión. En comparación con herramientas como Flyway, Liquibase o incluso el sistema de migración Rails, que permiten migraciones descendentes y control de versiones bidireccional, D1 ofrece un flujo unidireccional. Esto funciona bien cuando la migración está bien probada y se realiza exactamente según lo planeado. Cuando no es así, las opciones de recuperación son limitadas y es necesario estar preparado antes de que ocurra el problema, no durante.
Cómo funciona el sistema de migración de D1
wrangler d1 migrations create NOME crea un archivo .sql numerado en el directorio del proyecto migrations/. El número es secuencial y determina el orden de aplicación: 0001_create_users.sql, 0002_add_status_column.sql y así sucesivamente. Wrangler rastrea qué migraciones ya se han aplicado en una tabla interna llamada D1_MIGRATIONS dentro de la propia base de datos.
wrangler d1 migrations apply NOME_DO_BANCO aplica todas las migraciones pendientes en orden. wrangler d1 migrations list --remote muestra el estado actual: cuáles se han aplicado y cuáles están pendientes. Este flujo es suficiente para la mayoría de los casos.
La limitación estructural: no existe --rollback. Una migración aplicada a una base de datos D1 no se puede deshacer automáticamente. Si la migración 0015 introdujo un error en el esquema y necesita revertirlo, hay dos opciones. La primera es escribir la migración 0016 que deshace manualmente lo que hizo 0015; posible para operaciones no destructivas como agregar una columna, pero imposible para operaciones que eliminan datos, como DROP COLUMN o DROP TABLE. El segundo es utilizar Time Travel de D1 para restaurar la base de datos a un punto anterior a la migración, disponible para planes pagos con una ventana de 30 días.
El problema de coherencia del esquema en el borde
La replicación D1 crea un riesgo de implementación que los bancos tradicionales no tienen: la migración puede realizarse en el servidor principal mientras las réplicas aún cargan el esquema anterior. Un trabajador que lee desde una réplica desactualizada ejecutará consultas en un esquema diferente al esperado.
El escenario concreto: agrega la columna status a la tabla orders con la migración 0020. La migración se ejecuta en el primario. Simultáneamente, implementa el trabajador actualizado que genera SELECT status FROM orders. Una solicitud que llegue a una réplica que aún no ha recibido la migración fallará con un error de columna desconocida, incluso si la implementación fue bien y el principal ya tiene el esquema correcto.
El intervalo de propagación puede alcanzar los 60 segundos. La solución es separar la implementación de la migración de la implementación del código. El flujo correcto: aplicar la migración, esperar explícitamente durante al menos 60 segundos y luego implementar la nueva versión de Worker. Esta espera debe integrarse en la canalización de CI/CD; el wrangler deploy no tiene un indicador de "esperar para la propagación del esquema", por lo que debe crear este retraso manualmente. En la gran mayoría de los casos, un sleep 60 entre los dos pasos del proceso es suficiente.
Guía para migraciones seguras en producción
Antes de aplicar cualquier migración a una base de datos de producción, exporte un volcado completo: wrangler d1 export --remote --database NOME_DO_BANCO --output backup-$(date +%Y%m%d-%H%M).sql. Este archivo es su ruta de recuperación manual en caso de que algo salga mal y Time Travel no esté disponible o no sea suficiente.
Pruebe la migración en una base de datos provisional con datos de volumen equivalente a los de producción. Una migración que se ejecuta en 50 ms en una tabla con 1000 filas puede tardar 20 segundos en una tabla con 5 millones de filas y, durante esos 20 segundos, es posible que la base de datos no esté disponible para consultas que dependen de la tabla que se está cambiando. D1 no tiene reindexación en segundo plano como PostgreSQL con CREATE INDEX CONCURRENTLY.
Para cambios de esquema que no requieren tiempo de inactividad, utilice el patrón de implementación por fases. Para cambiar el nombre de una columna, procese el proceso en pasos independientes: primero, agregue la nueva columna como anulable; en segundo lugar, implemente el código que escribe en ambas columnas (antigua y nueva); tercero, un trabajo de reposición que copia datos de la columna antigua a la nueva en los registros existentes; cuarto, actualice el código para leer solo desde la nueva columna; quinto, elimine la columna anterior en una migración posterior. La combinación de todos estos pasos en una sola migración crea una ventana de inconsistencia y no permite una reversión parcial.
Probar migraciones localmente antes de entrar en producción
wrangler dev --local crea un archivo SQLite real en .wrangler/state/v3/d1/. Puede aplicar migraciones a este archivo con wrangler d1 migrations apply NOME --local, inspeccionarlo directamente con el cliente sqlite3 y ejecutar EXPLAIN QUERY PLAN en las consultas para verificar que los índices se utilicen correctamente antes de cualquier implementación.
La brecha entre lo local y lo remoto es la replicación. El entorno local es una instancia de SQLite pura sin la capa primaria ni réplicas; eventuales problemas de coherencia no aparecerán en las pruebas locales. Para cubrir esta brecha, cree un banco provisional D1 separado en su cuenta de Cloudflare, aplique las migraciones allí primero y valide el comportamiento con datos que se aproximen al volumen de producción.
Viajar en el tiempo es el plan B cuando todo lo demás falla. wrangler d1 time-travel restore --timestamp="2026-10-07T08:00:00Z" restaura el banco al estado de ese momento, dentro de un período de 30 días en planes pagos. Esto recupera datos eliminados por migraciones destructivas y revierte los cambios de esquema que no se pueden deshacer mediante una migración hacia adelante. La operación reemplaza el estado de toda la base de datos: no hay restauración selectiva de tablas específicas. Si la migración dañó una tabla pero otras tablas tuvieron actividad normal en el intervalo, la restauración también revertirá estas otras tablas a su estado anterior.
Lea también
- Cloudflare D1: La base de datos SQLite en el borde, y por qué "borde" no significa lo que parece
- D1 en producción: rendimiento, límites y lo que no escala por sí solo
- Consultas lentas en D1: cómo diagnosticar y optimizar
- Trabajadores y Páginas: despliegue, enrutamiento y lo que esconde cada modelo
- API GraphQL modernas: diseño de esquemas, rendimiento y patrones que funcionan
- Equilibrio de carga y dirección geográfica de Cloudflare: cuando el DNS se convierte en una capa de tráfico inteligente
