View Migrations: Version-Controlled Database Views for Laravel

Database views are powerful but awkward to manage. You either write raw SQL in migrations, maintain brittle CREATE OR REPLACE statements, or just avoid views altogether. View Migrations makes views as easy to manage as any other part of your schema.

Write SQL, Not Migrations

Create a view by dropping a SQL file in database/views/:

-- database/views/user_stats.sql
SELECT
    user_id,
    COUNT(*) as total_orders,
    SUM(amount) as total_spent,
    MAX(created_at) as last_order_at
FROM orders
GROUP BY user_id;

Then run:

php artisan view:migrate

That's it. The view is created in your database.

Content-Hash Change Detection

View Migrations computes a hash of each SQL file's content. On subsequent runs, it compares the current hash against what's stored in the migrations table. Views are only updated when their content actually changes — no unnecessary DROP and CREATE cycles.

php artisan view:status

+-------------+--------------+--------------+--------+
| View        | File Hash    | DB Hash      | Status |
+-------------+--------------+--------------+--------+
| user_stats  | a1b2c3d4e5f6 | a1b2c3d4e5f6 | OK     |
| new_report  | e5f6a1b2c3d4 |            | New    |
+-------------+--------------+--------------+--------+

Safe Operations

Preview changes before applying them:

php artisan view:migrate --dry-run

Clean up views that no longer have corresponding SQL files:

php artisan view:migrate --drop-orphans

Use in Laravel Migrations

You can also trigger view migrations from standard Laravel migration files:

use Laratusk\ViewMigrations\Facades\ViewMigrator;

return new class extends Migration {
    public function up(): void
    {
        ViewMigrator::migrateView('analytics_summary');
    }

    public function down(): void
    {
        ViewMigrator::dropView('analytics_summary');
    }
};

Event System

View Migrations fires events for each operation — ViewCreated, ViewUpdated, ViewDropped, and ViewMigrationCompleted — so you can hook into the lifecycle for logging, notifications, or cache invalidation.

Multi-Database Support

Works with MySQL, PostgreSQL, and SQLite out of the box. The package detects your database driver and generates the appropriate DDL statements automatically.

Check out the full documentation on GitHub.

View on GitHubStar the repo, explore the source code, and get started.
Go to Repository
Share this post
Back to Blog