Difflock: Lint Laravel Migrations Against Live Schema | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Laravel](https://www.msaied.com/public/articles?category=laravel)
6. /
7. Difflock: Lint Laravel Migrations and Diff Your Database Schema

   [Laravel](https://www.msaied.com/public/articles?category=laravel) [Composer Pacakge](https://www.msaied.com/public/articles?category=composer-pacakge) 

 Difflock: Lint Laravel Migrations and Diff Your Database Schema
================================================================

 Difflock is a Laravel package that lints pending migrations against your live database schema, records schema baselines, guards migrations in CI, and exposes MCP tools for AI coding agents.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 20 Sep 2026 · Updated 22 Sep 2026 · 4 min read

ShareCopy linkCopied

 ![Difflock: Lint Laravel Migrations and Diff Your Database Schema](https://cdn.msaied.com/690/f125c0f9698cce9dd5e241f7030543ba.png) 

  On this page +1. [What Is Difflock?](#what-is-difflock)
2. [Linting Pending Migrations](#linting-pending-migrations)
3. [Recording and Diffing Schema Baselines](#recording-and-diffing-schema-baselines)
4. [CI Integration and Migration Guard](#ci-integration-and-migration-guard)
5. [MCP Support for AI Coding Agents](#mcp-support-for-ai-coding-agents)
6. [Installation](#installation)
7. [Key Takeaways](#key-takeaways)

 What Is Difflock?
-----------------

Difflock is a Laravel package by [Rati Rukhadze](https://github.com/Heyosseus) that analyses pending migrations against the live database they will change. Rather than executing migrations against an empty test database, it reads migration source statically and combines that with the real schema and table-size metadata to surface problems before deployment.

Linting Pending Migrations
--------------------------

Run `difflock:lint` to analyse every pending migration:

```bash
php artisan difflock:lint
php artisan difflock:lint -v
php artisan difflock:lint --rule=drop-column

```

Consider this migration that looks harmless in a pull request:

```php
Schema::table('orders', function (Blueprint $table) {
    $table->string('channel');
    $table->foreignId('customer_id')->constrained()->cascadeOnDelete();
    $table->string('card_number', 32)->nullable();
    $table->index('status');
});

Schema::table('customers', function (Blueprint $table) {
    $table->dropColumn('legacy_token');
    $table->renameColumn('name', 'full_name');
});

```

On a populated database, Difflock flags the non-null `channel` column (no default, will fail on existing rows), the destructive `dropColumn()`, the rename, and the fact that `cascadeOnDelete()` removes child rows inside the database engine — bypassing model events, observers, and soft deletes.

Additional rules cover `change-column` (compares a `->change()` call with the live column definition), `unindexed-foreign-key`, and `redundant-index` (e.g., adding an index on `(status)` when `(status, created_at)` already exists).

When no pending migrations exist, the command audits all migration files instead of producing an empty report. Existing projects can accept their current backlog with:

```bash
php artisan difflock:lint --all --accept

```

This writes `database/difflock/accepted.json` as a baseline for future findings.

Recording and Diffing Schema Baselines
--------------------------------------

Difflock records an observed schema rather than rebuilding an expected one from migration history, which avoids interpreting migrations that contain conditionals, loops, or raw SQL.

```bash
php artisan difflock:diff --save

```

This writes `database/difflock/schema.json` — commit it to version control. Later runs compare the current connection against that snapshot. You can also compare two configured connections directly:

```bash
php artisan difflock:diff --from=staging --to=production

```

The baseline captures tables, columns, indexes, defaults, and foreign keys. It never stores row data or credentials.

CI Integration and Migration Guard
----------------------------------

Installing Difflock does not alter `php artisan migrate`. The guard only activates when you use its own command:

```bash
php artisan difflock:migrate

```

When findings reach the configured block level, it stops before Laravel writes to the database. Use `--allow-risky` to deliberately bypass the guard; Laravel's `--force` flag remains the separate production confirmation.

For CI pipelines, a single command covers both drift detection and migration linting:

```bash
- run: php artisan difflock:check --ci

```

Exit codes: `0` = pass, `1` = drift or findings at threshold, `2` = check cannot run.

MCP Support for AI Coding Agents
--------------------------------

`php artisan difflock:mcp` starts a standalone MCP server over stdio. Its four tools provide table context, migration linting, schema-drift checks, and rule documentation. An AI coding agent can check a migration before writing the file, using the live schema and table statistics. The `difflock:explain` command generates a Markdown briefing for a migration without calling any external API.

Installation
------------

Difflock 1.0.0 requires PHP 8.3 and supports Laravel 12 and 13. It works with MySQL, MariaDB, PostgreSQL, and SQLite.

```bash
composer require heyosseus/difflock --dev
php artisan vendor:publish --tag=difflock-config
php artisan difflock:doctor

```

`difflock:doctor` reports the connection, available tables, pending migrations, registered rules, and whether the configured database role can write.

Key Takeaways
-------------

- Lints migrations against the **live schema**, catching issues an empty test database misses
- Detects destructive operations: `dropColumn`, non-null columns on populated tables, cascade deletes
- Records JSON schema baselines you can commit and diff across environments or connections
- Guards `php artisan migrate` with configurable block levels and CI-friendly exit codes
- Exposes MCP tools so AI coding agents can check migrations before writing them to disk
- Requires PHP 8.3, supports Laravel 12 and 13, MySQL, MariaDB, PostgreSQL, and SQLite

---

Source: [Difflock: Lint Laravel Migrations and Diff Your Schema — Laravel News](https://laravel-news.com/difflock-migration-linter)

- [Laravel](https://www.msaied.com/public/articles?search=Laravel)
- [Migrations](https://www.msaied.com/public/articles?search=Migrations)
- [Database](https://www.msaied.com/public/articles?search=Database)
- [CI/CD](https://www.msaied.com/public/articles?search=CI%2FCD)
- [Schema](https://www.msaied.com/public/articles?search=Schema)
- [Linting](https://www.msaied.com/public/articles?search=Linting)

 Frequently asked questions 
---------------------------

  Does Difflock modify or execute my migrations when linting them?No. Difflock reads migration source statically without loading or executing it. It combines that static analysis with your live schema and table-size metadata to flag potential issues, leaving your database untouched during the lint step.

   Does installing Difflock change how `php artisan migrate` behaves?No. Installing Difflock does not alter the standard `migrate` command. The migration guard only activates when you explicitly run `php artisan difflock:migrate`. You can also bypass the guard with `--allow-risky` when needed.

   What does the schema baseline file contain, and is it safe to commit?The `database/difflock/schema.json` baseline contains schema structure — tables, columns, indexes, defaults, and foreign keys. It does not include table rows or database credentials, so it is safe to commit to version control.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleFast Excel 5.x Adds Streaming Imports and Safer Exports for Laravel](https://www.msaied.com/public/articles/fast-excel-5x-adds-streaming-imports-and-safer-exports-for-laravel) [Next articleHealth for Laravel: Kubernetes Probes and Prometheus Metrics](https://www.msaied.com/public/articles/health-for-laravel-kubernetes-probes-and-prometheus-metrics)  

   On this page
-------------

1. [What Is Difflock?](#what-is-difflock)
2. [Linting Pending Migrations](#linting-pending-migrations)
3. [Recording and Diffing Schema Baselines](#recording-and-diffing-schema-baselines)
4. [CI Integration and Migration Guard](#ci-integration-and-migration-guard)
5. [MCP Support for AI Coding Agents](#mcp-support-for-ai-coding-agents)
6. [Installation](#installation)
7. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
