Difflock vigila las migraciones antes de producción
Un linter para Laravel que analiza migraciones con el estado real de la base de datos antes de dejarlas pasar.
El problema no es solo que una migración funcione
Una migración puede pasar una revisión, funcionar sobre una base de datos vacía y seguir siendo una mala idea en producción. Añadir una columna obligatoria sin valor por defecto, eliminar una columna o crear un índice sobre una tabla con datos no son cambios equivalentes a hacer lo mismo durante los tests. El código de la migración no cuenta toda la historia: también importan el esquema actual y el tamaño de la tabla afectada. (github.com)
Difflock es un paquete para Laravel que añade esa información al análisis. Lee las migraciones pendientes de forma estática y consulta el esquema de la conexión configurada para detectar cambios que merecen revisión. La idea no es decidir por mí, sino impedir que una operación destructiva o potencialmente costosa llegue a producción sin que nadie la haya mirado de forma consciente. (github.com)
Qué revisa antes de ejecutar cambios
El paquete detecta, entre otros casos, eliminaciones de tablas y columnas, renombres, cambios mediante change(), índices y claves foráneas. Algunas reglas dependen del número de filas de la tabla, por lo que el mismo código puede recibir una evaluación distinta en una tabla vacía y en otra con datos. También puede comparar el esquema actual con un baseline guardado para descubrir drift: cambios hechos directamente en la base de datos o diferencias respecto al estado que el equipo había aceptado. (github.com)
Para empezar, la instalación y el flujo básico son bastante directos. Primero guardaría un baseline del esquema que considero válido, después ejecutaría el linter sobre las migraciones pendientes y, finalmente, llevaría ambas comprobaciones al pipeline. Difflock requiere PHP 8.3 o superior y está orientado a Laravel 12 y 13. (github.com)
composer require heyosseus/difflock --dev
php artisan difflock:diff --save
php artisan difflock:lint
php artisan difflock:check --ciEl comando difflock:diff compara el esquema contra el baseline o entre dos conexiones indicadas con --from y --to. difflock:lint analiza por defecto las migraciones pendientes, mientras que difflock:check --ci reúne el análisis de drift y migraciones con un código de salida útil para integración continua. Si necesito revisar el histórico completo, existe difflock:lint --all, pero no empezaría activándolo como bloqueo en un proyecto antiguo sin tratar antes los avisos existentes. (github.com)
Un bloqueo que hay que elegir explícitamente
Lo interesante no es solo informar, sino poder usar php artisan difflock:migrate en lugar de lanzar la migración directamente. Ese comando analiza primero las migraciones pendientes y solo delega en el migrate de Laravel si no se alcanza el nivel configurado en protection.block_on. Si he revisado el riesgo y quiero continuar, puedo hacerlo de forma explícita con --allow-risky; no es una decisión que deba quedar escondida en un script. (github.com)
La configuración publicada permite ajustar la conexión, la ubicación del baseline y los umbrales de riesgo. Yo empezaría con una política conservadora y cambiaría los límites solo cuando tenga una razón concreta relacionada con el volumen o el patrón de despliegue de la aplicación. También revisaría los ignore: sirven para quitar hallazgos, no para mejorar una migración que sigue siendo dudosa. (github.com)
// config/difflock.php
return [
'baseline' => env('DIFFLOCK_BASELINE', database_path('difflock/schema.json')),
'risk' => [
'fail_on' => env('DIFFLOCK_FAIL_ON', 'critical'),
],
'protection' => [
'enabled' => env('DIFFLOCK_PROTECTION_ENABLED', true),
'block_on' => env('DIFFLOCK_BLOCK_ON', 'critical'),
],
];La letra pequeña importa
Difflock no sustituye una estrategia de migraciones compatible con despliegues progresivos. No puede garantizar ausencia de bloqueos ni cero tiempo de caída, porque eso depende del motor, su versión, la configuración y, en algunos casos, de los datos. Tampoco sabe qué consultas ejecuta mi aplicación, así que puede avisar de que elimino un índice, pero no afirmar si eso degradará una consulta concreta. (github.com)
Hay otra limitación importante: las migraciones son PHP ejecutable, pero Difflock las analiza sin ejecutarlas. Por eso puede marcar como condicional una operación dentro de un if, no resolver nombres construidos dinámicamente y avisar cuando encuentra SQL crudo mediante DB::statement(). Me parece un enfoque correcto: inventar certezas sobre código que no puede interpretar sería peor que reconocer que falta contexto. (github.com)
Tampoco se engancha automáticamente a php artisan migrate. Hay que adoptar difflock:migrate o añadir difflock:check --ci al proceso de entrega para que actúe como barrera real. SQLite merece una mención aparte: ofrece menos metadatos que MySQL, MariaDB o PostgreSQL, y el paquete no puede comparar longitudes o precisiones que el driver no expone. (github.com)
Dónde lo incorporaría
Yo lo pondría primero en CI con php artisan difflock:check --ci, sin convertir de golpe un proyecto heredado en una colección de builds rojos. Después generaría y versionaría el baseline, revisaría los hallazgos antiguos y aceptaría únicamente el backlog que el equipo ya conoce. A partir de ahí, cada migración nueva tendría que justificar sus cambios de esquema antes de llegar a producción. (github.com)
Para aplicaciones Laravel con tablas que ya tienen volumen, este tipo de comprobación aporta una capa útil entre el código y la base de datos real. No reemplaza el criterio técnico, una copia de seguridad ni un plan de despliegue, pero obliga a hacer visible el riesgo cuando todavía es barato corregirlo. Esa es una función bastante más valiosa que otro comando que simplemente confirma que la sintaxis parece correcta.
Fuente: Laravel News Documentación oficial: Difflock en GitHub