cycle/migrations
Cycle Database Migrations provides structured, versioned database schema changes for PHP applications. Configure a migrations directory and vendor paths, initialize the migration table, then run migrations programmatically or generate migration files during schema compilation.
Architecture fit — first, a correction to the record. The prior assessments in this bundle (assessment-pm.md, assessment-tpm.md) describe cycle/migrations as a Laravel/Eloquent package that integrates with Illuminate\Support\Facades\Schema, php artisan make:migration, and Laravel's Migrations facade. This is factually wrong and should be corrected before it reaches a decision log. cycle/migrations is the migration component of the Cycle ORM / Spiral Framework ecosystem (namespace Cycle\Migrations, formerly Spiral\Migrations). It has no service provider, no Artisan commands, no Eloquent awareness, and no Laravel integration of any kind. It operates on Cycle\Database (DatabaseManager, driver configs, TableBlueprint) and is driven programmatically:
$migrator = new Migrations\Migrator($config, $dbal, new Migrations\FileRepository($config));
$migrator->configure();
while (($migration = $migrator->run()) !== null) { /* ... */ }
Any roadmap commitment built on the premise "generate migrations from Eloquent models with one command" is built on a package that cannot do that.
What the package actually is. A small, focused schema-versioning library: a Migrator orchestrator, a FileRepository for on-disk migration files, a MigrationConfig (migration directory, vendorDirectories, tracking table, safe flag), and a TableBlueprint DSL for writing up()/down() in PHP. Its headline capability — automatic migration generation from a compiled schema — lives in a separate package, cycle/schema-migrations-generator. That is a material procurement detail: adopting "automatic migration generation" means vetting two repositories, two release cadences, and two maintenance trails, not one.
Integration feasibility. Feasible and straightforward if and only if the surrounding stack already uses Cycle\Database as its DBAL. In that case the API surface is tiny and the mental model is conventional (ordered files, a ledger table, up/down). The vendorDirectories option is a genuinely useful primitive for modular monoliths and internal package distribution, and the safe flag supports non-interactive CI execution. Outside that context, adoption means pulling in a parallel database abstraction layer purely to run DDL — technically possible, organizationally expensive.
Technical risk. Code-level risk is low: MIT license, small dependency footprint, active patch releases (v4.2.4–v4.2.6 show read-only-schema handling, Psalm/CS hardening, PHP 8.4 deprecation fixes, and a foreign-key ordering fix). The real risks are stack-mismatch risk and bus-factor risk. 21 stars and zero declared dependents means the community is effectively the Spiral user base; maintenance is single-vendor (Spiral Scout). Version 4.0 was a breaking release driven by an upstream framework change (Spiral 3.0 / new Reactor), which tells you the release cadence is coupled to that framework's evolution rather than to a stable public contract.
Key questions to resolve before any commitment:
cycle/schema-migrations-generator) or only the runner? The scope and risk profile differ substantially between "one library" and "two."Stack fit — the honest verdict. For a Laravel-standardized organization, the correct integration approach is not to integrate this package. Illuminate\Database\Migrations already provides migration generation, a version ledger, rollback, batching, and — critically — an installed base of engineers and documented patterns. Layering cycle/migrations alongside it produces two competing schema authorities and no commensurate gain. Adoption is defensible in three narrower situations: (1) a service already running Spiral/Cycle ORM that needs vendor-package migrations; (2) a framework-agnostic internal PHP library that must ship schema changes with itself; (3) a context where migrations must be invoked from application/runtime code rather than a CLI — the while ($migrator->run()) loop is well-suited to long-running workers (RoadRunner, Swoole) and bootstrap scripts, which is a genuine differentiator versus Artisan-centric tooling.
Migration path. Two distinct paths, and they should not be conflated:
spiral/migrations: the v3.0 rename to Cycle\Migrations is a namespace-and-config swap; v4.0's Atomizer/Reactor rework is the breaking boundary. Plan a dedicated upgrade ticket with a full generate→run→rollback rehearsal.cycle/migrations ledger at a baseline snapshot, and leave the existing Laravel ledger untouched on its own schemas. Never point both runners at one schema.Compatibility checks to run in a spike (timebox: 2–3 days).
cycle/database version constraints against existing doctrine/dbal/PDO-adjacent packages. Expect resolvable, but pin explicitly in composer.json rather than floating ^4.0.first/after, CURRENT_TIMESTAMP), and foreign-key index behavior have all been patched recently, which suggests non-uniform maturity across engines.Sequencing.
configure → generate → review → run → rollback → re-run) on a throwaway database matching production engine.Migrator in a thin internal adapter/CLI (bin/db-migrate) so application code and CI depend on our interface, not on Cycle\Migrations directly. This is the single highest-leverage step for reversibility.safe: false everywhere except the automated pipeline, where confirmation is surfaced as a pipeline approval gate instead.cycle/schema-migrations-generator as a separate adoption decision.Maintenance. Low ongoing effort, non-trivial ownership cost. The package changes slowly and mostly in response to PHP releases and upstream framework shifts. MIT licensing means we can fork, but a fork of a migration tool becomes internal infrastructure with no upstream to lean on — budget that as a contingency, not a plan. Track releases monthly rather than pinning blindly; the 4.2.x line has shipped meaningful correctness fixes (foreign-key ordering, binary sizing, array_multisort argument ordering, read-only schema skipping) that we would want.
Support. No commercial support tier for the package itself; support flows through the Spiral Scout community channels and the source code. Documentation is README-level — installation, configuration, a run loop, and a pointer to the generator. Engineers will read Migrator, FileRepository, and TableBlueprint to answer non-trivial questions. Factor this into onboarding estimates explicitly rather than assuming "it's just migrations."
Scaling. Runtime cost is per-migration DDL, so scaling is a function of schema-change volume, not traffic — not a concern. The scaling concern is concurrency: multiple app replicas or parallel CI jobs racing the same ledger. Implement a lock (advisory lock, or a lease row in the tracking table) at the wrapper layer. vendorDirectories scales fine for a handful of packages; ordering and precedence across many vendor directories is where it gets fragile, so keep the list short and explicit.
Failure modes to instrument for.
safe: true leaking into a production path — this flag suppresses the confirmation prompt. Gate it at the CLI wrapper, not in the shared config object.migrations table.Ramp-up. For a PHP engineer who has used any migration tool: approximately 1–2 days to first productive migration, with the learning curve concentrated in the TableBlueprint DSL and the migrator lifecycle. Add 0.5–1 day if cycle/schema-migrations-generator is in scope. Add 1 day for whoever writes the internal wrapper and CI integration. Compare against roughly 2 hours for an engineer already fluent in Laravel migrations — that delta is the clearest single argument against adoption in a Laravel shop.
TPM recommendation. Do not adopt on the basis of the existing assessments; they describe a different package. Re-open the evaluation as a conditional no for Laravel-standardized services and a conditional yes for Cycle/Spiral or framework-agnostic PHP services where runtime-invoked migrations or vendor-package migrations are a real requirement. Require a 2–3 day spike with the adapter-wrapper deliverable before any roadmap commitment, and treat the generator as a separate, later decision.
How can I help you explore Laravel packages today?