Skip to content

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.

Published · Updated · 4 min read

Difflock: Lint Laravel Migrations and Diff Your Database Schema

What Is Difflock?

Difflock is a Laravel package by Rati Rukhadze 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:

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:

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:

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.

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:

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:

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:

- 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.

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

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

About the author

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 GitHub LinkedIn WhatsApp Email Address My CV

Have a technical challenge?

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

Discuss your project