dragon-code/laravel-migration-actions
Laravel Migration Actions lets you attach custom action classes to migrations and run them automatically around schema changes, so data setup, cleanup, and other migration-related tasks stay organized alongside the migrations that need them.
What it is: A Laravel package that lets a team define "actions" — classes with up()/down() methods, tracked the same way migrations are tracked — and run them during deployment. It turns ad-hoc one-off scripts (data backfills, cache flushes, seeding lookup tables, config migrations) into versioned, once-only, reviewable deploy steps. Release 7.3.0 confirms a capability that was previously only implied: actions can also be dispatched as queued jobs, with configurable job class and uniqueness-lock duration, and the command supports Laravel-style --isolated execution.
Architecture fit: Strong for any Laravel codebase already living on php artisan migrate. The package follows standard Laravel package conventions: PSR-4 autoloading, service provider auto-discovery, an artisan generator command, and an execution record kept in a database table so actions do not re-run. It remains additive — it does not touch the ORM, routing, or the migration runner itself.
What 7.3.0 changes about the fit: the package now has a second execution surface. Actions can run inline in the release or be handed to your queue workers. That is architecturally the right call — it decouples long-running data work from the deploy window — but it means the package is no longer purely deploy-time tooling. It now depends on your queue connection, worker capacity, retry/timeout policy, and a shared cache lock store. Teams already comfortable with migrate still need no new mental model for the core concept; they do need a mental model for queue topology.
Integration feasibility: Still low. composer require, generate an action class, commit it, add one command to the deploy pipeline. Realistic pilot is now one engineer for three to four days: two to three days to convert existing deploy-script hacks and stand up the inline path, plus roughly half a day to decide queue connection/name, job class override, and lock TTL if you intend to use the queued path at all.
Technical risk:
--isolated fix ("match Laravel core presence semantics") means the package now uses Laravel's Isolatable behaviour, i.e. a cache-backed atomic lock, rather than whatever it did before. This was previously flagged as the single most important unknown. The remaining risk is environmental: isolation is only real if the lock store is genuinely shared and atomic (Redis, memcached, or the database cache driver). On array or per-container file cache in a rolling Kubernetes deploy, isolation is theatre. Verify the store before trusting the flag.mark-year13) landing in a 7.3.0 minor release, on an established 7.x line, is better evidence of a functioning contributor pipeline than the previous assessment credited. It does not eliminate single-vendor concentration, but it weakens the "no downstream constituency" concern at the margin.queue.job config gives you a clean place to inject tracing, timeouts, retry policy, or tenant context without forking. It also lowers the cost of a future fork, since the most opinionated part of the queued path is now yours to own.laravel-migration-actions, repository laravel-deploy-operations. Confirm the canonical composer name matches the repository you are auditing, or your dependency scanner watches the wrong thing.down() may not cleanly reverse. Design property of the domain, not a package defect — but the queued path adds ambiguity about when the operation actually happened.--pretend/dry-run, batching/transaction helpers, or a testing helper for asserting actions in CI. Carry these forward as open questions.Key questions for the maintainer / spike (revised):
--isolated now follows Laravel core semantics. Verify: which cache store does it bind to, is it configurable, and what does it do when the store doesn't support atomic locks?migrations table or a dedicated table, and what happens if that table is absent or behind?Isolatable contract — and is there a CI matrix proving it?Stack fit: Fits any Laravel service on a version that provides the Isolatable contract (verify — this is Laravel 10.x-era core behaviour), and slots naturally into the deploy tooling most teams already use — Envoyer, Forge, Deployer, GitHub Actions, GitLab CI, or a Kubernetes pre-upgrade Job/init container. The natural insertion point is immediately before or after php artisan migrate in the release script. The queued path additionally requires a working queue connection and worker pool, which most Laravel services already have for other reasons — meaning the marginal infrastructure cost is usually zero, but the coupling is new.
Migration path: Do not rip out existing deploy scripts. Layer the package in:
--isolated to prove the lock store works.Compatibility: Pin the version explicitly in composer.json and verify the constraint against your Laravel minor. 7.3.0 is a minor release and the three changes are additive or corrective rather than breaking, so the upgrade itself is low risk. Test against every database driver you actually run (transaction and locking semantics differ materially between MySQL, PostgreSQL, and SQL Server), and separately test against every cache driver you run — the isolation guarantee now depends on it. If you run multiple database connections, confirm which connection execution records are written to; if you run multiple queues, confirm which one the operations dispatch to.
Sequencing:
--isolated and the queued path's completion semantics.queue.job override if you want tracing without touching the package.Maintenance: The package itself is small and stable — expect near-zero ongoing maintenance from the package side, and 7.3.0 is a non-breaking minor you can take at leisure. The maintenance burden is entirely yours: the actions you write are production data operations and need the same review rigor as migrations. Budget for a periodic (quarterly) check on upstream activity and Laravel major-version compatibility, with a standing decision point to fork. The queue.job config hook reduces the cost of a break — you can patch behaviour from your own class rather than waiting upstream.
Support: MIT, community-supported, effectively single-maintainer — but the 7.3.0 contributor activity is a genuine improvement in the bus-factor signal. Treat it as unsupported software with a good idea behind it and an increasingly credible contributor base. Name an internal owner, document the package in your runbook, and be prepared to vendor the small codebase if a Laravel upgrade breaks it. Do not put it on a critical path where a stalled upstream would block a framework upgrade.
Scaling: Inline execution is once-per-deploy by design, so steady-state cost is negligible. The queued path shifts, rather than adds, cost:
--isolated as a second line of defence — not the only one. Verify the lock store is shared and atomic.UPDATE — and if queued, chunk at the job level so a failure retries a bounded unit rather than the whole backfill.Failure modes to design for:
down(). Chunking limits blast radius.down().queue.job override for local patching, fork readiness.Ramp-up: Still very low for the core concept — the vocabulary is familiar (up/down, tracked execution, artisan), so a Laravel developer is productive in under an hour. 7.3.0 adds one genuinely new thing to teach: the queued path, and with it the notion that a deploy can be "done" while its data operations are still pending. Budget a short internal write-up covering (a) inline versus queued decision criteria, (b) lock TTL guidance, (c) how to verify operations completed, and (d) the code-review checklist treating actions as production data operations. That artifact matters more than the package.
How can I help you explore Laravel packages today?