Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Migrations Laravel Package

doctrine/migrations

Doctrine Migrations is a database schema migration library for PHP, letting you version and track schema changes with a robust CLI and API. It integrates with Doctrine DBAL and ORM to safely apply, roll back, and manage migrations across your projects.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Release delta (3.9.8). A two-PR patch release with no new features and no breaking changes. The substantive item is PR #1597, which fixes a doctrine/dbal 4.5 deprecation surfaced from within the migrations engine; the second PR is a Dependabot CI bump. Net effect on the assessment: it materially strengthens the DBAL-coupling risk item below, adds one small deprecation-hygiene consideration for our CI, and leaves every other finding unchanged.

Architecture fit. doctrine/migrations is a standalone, framework-agnostic migration engine built on doctrine/dbal and symfony/console. It is not a Laravel package in any meaningful sense: Laravel already ships Illuminate\Database\Migrations with its own migrations table, its own artisan command surface, and its own repository model. Adopting this package does not extend Laravel's migration system — it stands up a second, parallel one. That is the central architectural fact of this evaluation, and every downstream risk flows from it.

The package's genuine differentiator is diff generation: migrations:diff compares Doctrine ORM mapping metadata against live schema introspection and emits versioned migration classes. That value only materialises if we are using Doctrine ORM (via laravel-doctrine/orm or equivalent). If the application is Eloquent-first, we would be adopting a heavier engine, a second version table, and a Symfony Console dependency chain to hand-write the same SQL we already hand-write — a net negative.

Integration feasibility. Technically feasible, but only under a scoped ownership model. The package is consumed inside a Laravel app by registering a Configuration object (migrations paths, table_storage, all_or_nothing, transactional, schema_filter) via a service provider, then either invoking the library's command classes directly or registering them as artisan commands. This is well-trodden ground through community bridges; it is also entirely bespoke — no first-party support, no Laravel documentation, no upgrade contract.

Technical risk. Ranked:

  1. Schema ownership collision (high). migrations:diff proposes dropping tables that exist in the database but are absent from Doctrine ORM metadata. In a mixed Eloquent/Doctrine app, an unconfigured schema_filter will generate destructive migrations against Eloquent-owned tables. This is the single most likely production incident and must be mitigated by configuration and CI gating, not review discipline.
  2. Two sources of truth (high). Two version tables mean two answers to "what schema is deployed." Drift is invisible until an incident.
  3. Non-transactional DDL (high). On MySQL, DDL implicitly commits. all_or_nothing and transactional provide far weaker guarantees than the configuration names imply — a mid-migration failure can leave partial schema applied with no version row recorded, requiring manual reconciliation via migrations:version.
  4. doctrine/dbal major-version coupling (medium — revised downward, directionally). Laravel ≤10 pins DBAL v3 for column modification support; Laravel 11+ removed that requirement, freeing DBAL v4. Any constraint conflict forces us onto an older doctrine/migrations line. 3.9.8 is the first release we can point at as evidence that the 3.9 maintenance line is actively tracking DBAL 4.5, so the combination "Laravel 11+, DBAL 4.5, migrations 3.9.x" is now a supported and tested path rather than an assumption. This does not remove the constraint math from the spike — it removes the suspicion that the 3.9 line is frozen against DBAL v4. If we are on DBAL 4.5, treat 3.9.8 as the version floor.
  5. 4.0 upgrade horizon (medium). Release notes explicitly reference an existing 4.0.x line. We would be adopting 3.9.x with a known major upgrade ahead of us, with no published migration guide evaluated here. Note the maintenance pattern: 3.9.x is receiving compatibility patches rather than features, which is consistent with 3.9 being a stabilisation branch while 4.0 absorbs development — good for us short term, and a firm clock on the upgrade.
  6. Concurrent execution (medium). The library does not arbitrate across runners. Multi-instance deploy topologies require an external lock or single-runner execution.
  7. Deprecation noise (low — new). The fact that a DBAL 4.5 deprecation originated inside the engine indicates our dependency floor matters more than usual. Estates running strict error handlers that promote deprecations to exceptions (common in PHPUnit and in some prod configurations) can see failures from library internals until the pinned version is high enough. Pin to 3.9.8 or later and surface deprecations in CI rather than in production.

Key questions.

  • Are we Doctrine ORM, Eloquent, or hybrid — and which schemas does each own?
  • Which database engines are in scope, and is DDL transactional on each?
  • On Laravel ≤10, can we accept a DBAL v3 pin that constrains the migrations version line? On DBAL 4.5, are we prepared to hold a >=3.9.8 floor?
  • Do any of our environments promote deprecations to exceptions, and would a library-internal DBAL deprecation break them?
  • What is the 4.0 timeline and who owns that upgrade?
  • What is our rollback policy — do we permit destructive down() in production?
  • Who is on call for a half-applied migration at 3am?
  • Is the dependents: 0 figure a data artefact? For a package that underpins DoctrineMigrationsBundle, it almost certainly is; it should be excluded from the decision.

Integration Approach

Stack fit. Adopt only if Doctrine ORM is genuinely part of the target architecture. The defensible pattern is bounded-context ownership: Doctrine owns schema for a specific domain (e.g., a new service module introduced with laravel-doctrine), Eloquent owns the legacy core, and the two never touch the same tables. This gives a clean configuration boundary — a dedicated migrations_paths namespace, a distinct table_storage.table_name, and a schema_filter regex that scopes diff generation to Doctrine-owned tables only.

The anti-pattern to reject outright is a whole-database switchover of an existing Eloquent application. The migration cost is a full rewrite of every historical migration into DBAL-compatible form, with no functional gain on tables that Eloquent already manages adequately.

Migration path.

  1. Spike (1 sprint). Install against the current Laravel and DBAL versions. Resolve constraint conflicts; where DBAL is 4.5, pin doctrine/migrations to ^3.9.8 as the floor. Prove migrations:diff against a throwaway schema with schema_filter configured, and verify that Eloquent-owned tables are excluded.
  2. Isolated pilot (1 sprint). One bounded context, non-critical, in staging. Establish the command wrapper, config provider, and CI gate.
  3. Production cutover for the pilot domain. Migrations run as a pre-deploy job, never on application boot.
  4. Retire the parallel path for that domain — archive any equivalent Laravel migrations so nothing can re-run them.

Compatibility. Verify against the actual Laravel and PHP versions in the estate, not the package's declared matrix. Symfony Console version alignment matters: recent releases added Symfony 8 component support, so a modern Laravel should align cleanly, but this needs confirmation in the spike rather than assumption. The doctrine/dbal resolution is the most likely blocker; 3.9.8 improves the odds on DBAL v4 but does not change the fact that this is a constraint-solving exercise performed at spike time. Add a deprecation-reporting step to CI so library-internal deprecations against our DBAL version are caught on upgrade, not in the deploy window.

Sequencing. Config and CI gating must land before the first real migration, not after. Concretely: migrations:diff --dry-run in CI to fail on ORM/schema drift; migrations:up-to-date (or status) as a deploy gate; migrations:migrate --dry-run output reviewed for destructive statements. Add the external lock before the second app instance exists. Because 3.9.x is patching dependency compatibility rather than shipping features, schedule a deliberate patch-review cadence (monthly is sufficient) rather than auto-merging: these updates change dependency floors, and a merged patch that raises the DBAL floor can invalidate a working deploy.

Operational Impact

Maintenance. Doctrine is foundation-backed with a small, stable core of maintainers (the release history is dominated by a handful of names) and a disciplined patch cadence. The 3.9.8 delta is instructive about what that cadence is now delivering: dependency-compatibility fixes from the community, plus Dependabot housekeeping. That is a healthy quality signal and a thin bus-factor signal — two contributors, one of them a bot. Observe also that 3.9.x is now in compatibility-only mode, which caps the surprise surface (no new features to regress) while guaranteeing ongoing floor movement in doctrine/dbal. We inherit the DBAL upgrade treadmill and the 4.0 transition as unplanned work; budget for it explicitly rather than treating it as incidental.

Support. MIT license, permissive and unproblematic. Documentation lives on doctrine-project.org, not in the repo — the README is a pointer only. There is no Laravel-specific guidance anywhere, so internal documentation is a deliverable, not a nice-to-have. Support for our integration layer is entirely ours. Note that a bugfix release at this granularity (one engine fix, one CI bump) is not a support event for us — but it is a reminder that our support model must include "read the patch notes and decide whether to bump," which needs a named owner.

Scaling. Three constraints bite:

  • Deploy concurrency. Migrations must run once, from one runner, behind a lock. Do not attach them to container entrypoints.
  • Large-table DDL. The library emits SQL; it does not orchestrate online schema change. For large MySQL tables we need gh-ost/pt-online-schema-change as a separate, hand-managed process, which partially defeats the tool's value on the tables that matter most.
  • Multi-tenancy. One metadata table per tenant is awkward with static migrations_paths. If multi-tenancy is on the roadmap, validate this before committing.
  • Read/write splitting. Laravel's read/write connection routing can send migration queries to a replica. Force the write connection explicitly.

Failure modes to document and rehearse.

  • Partial DDL application on MySQL with no version row — reconcile via migrations:version.
  • Metadata table absent on first run — requires sync-metadata-storage.
  • Path/namespace drift after a refactor — migrations silently not discovered.
  • schema_filter misconfiguration — destructive diff against Eloquent tables (the headline risk).
  • Accidental destructive down() execution in production.
  • DBAL major-version breakage in hand-written migration code.
  • Deprecation-to-exception failure from library internals on a DBAL version below the pinned floor (low likelihood; the reason for a >=3.9.8 pin).
  • Concurrent runner collision — duplicate DDL errors and inconsistent version state.

Ramp-up. The team's mental model is artisan: php artisan migrate, migrate:rollback, a single migrations table. This package asks them to learn Symfony Console invocation, namespaced migration paths, a second version table, and a diff workflow with a filtering language. The conceptual distance is modest but non-zero, and the failure modes are asymmetric — a mistake here is destructive schema change, not a bug. Plan one sprint of spike plus written runbook, and require a second engineer to review any generated migration before it executes. Do not let migrations:diff output ship unreviewed.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
thomas-0816/doctrine-dbal-duckdb
moyisoft/laravel-admin
oxygen/mod-pages
oxygen/mod-import-export
oxygen/mod-media
ksoft/laravel-contentbuilderjs
ourgoldpackages/exchange
mikkimike/laravel-exchange1c
wandesnet/mercadopago-laravel
tsfcorp/email
larafony/core
laravel-enso/currencies
tartan/laravel-online-payment
wedevbr/celcoin-laravel
surazdott/nepali-date
devsquad-cockpit/laravel
coding-socks/laravel-upload-handler
artisanbarista/laravel-shield
instance-code/repository
flooris/prestashop-models