statamic/migrator
Statamic Migrator brings Laravel-style migrations to content, letting you define repeatable migration classes that import and transform external data into Statamic collections and taxonomies, run via Artisan.
What this actually is — settle this first. The description is unambiguous: this is a one-shot content importer for Statamic v2 → v3, not a versioned schema-as-code migration tool. The competing reading in circulation (Laravel-style, reversible, rollback-able content-structure migrations) is a materially different product with a different lifetime and a different adoption plan. Treat the broader schema use case as unverified until the command surface is read. A half-day spike settles it: src/ServiceProvider.php, then src/Console/. Whether commands register under php please or php artisan is the tell. Until then, the documentation ambiguity is itself a risk finding — a first-party tool whose scope is contested in its own README is a tool whose behavior you verify rather than assume.
Architecture fit — low by construction, because there is no runtime footprint. The package operates on flat files: reads a v2 content tree, transforms, writes into a fresh v3 install. It never sits in the request path, never owns a database table, never serves a page. That means near-zero production blast radius and near-zero architectural coupling. It also means it is not infrastructure — it belongs on a throwaway migration branch in require-dev, pinned to an exact version, and should be deleted after cutover. The only scenario where that changes is if the spike proves the schema-migrations reading, which would make this a permanent architectural commitment requiring an explicit written decision (migrations as source of truth vs. Control Panel edits — pick one).
Integration feasibility — gated entirely by the version matrix, not by engineering effort. This tool exists to bridge one specific major-version pair. If you are not on v2 and not targeting v3, feasibility is zero and no amount of configuration changes that. If you are, the work is mapping work, not tooling work: fieldsets, custom fieldtypes, addon-owned data, globals/navs, forms, drafts and revisions, multisite/localization directories, asset metadata and focal points. The tool converts the mechanical copy into a configured run; the intellectual labor of deciding what "correct" means remains yours. Budget the counterfactual — roughly 2–6 engineer-weeks of bespoke ETL plus QA — as the business-case anchor, and treat the tool as compressing the mechanical share of that, not the whole of it.
Technical risk.
composer.json in week one — fork, bespoke ETL, or stop.down() is not a true inverse of content writes. Snapshot-based restore is the real rollback path.Key questions to answer before scoping.
please, artisan, or both?Stack fit. Laravel + Statamic v2 source, Statamic v3 target, PHP matching the package's declared matrix. No fit with a modern stack, and no fit with a non-Statamic source. Validate the matrix against your real toolchain at spike time, not at cutover.
Migration path — it is a ladder, and this is only the first rung. Frame it explicitly: v2 → v3 via this tool, v3 → v4/v5 via the vendor's own upgrade route. The adoption decision therefore hinges on the second hop. If the v3 output is upgrade-ready, this buys a cheap, reversible first step and unlocks supported versions and security patches sooner. If it is not, the plan is a time-boxed full re-platform and this tool is a partial accelerant for the content subset only. Either way, the decision is upgrade vs. rebuild vs. stay, and the tool's job is to make that decision cheap to answer.
Compatibility. Pin the exact version. Read composer.json for PHP/Laravel/Statamic constraints and any extension requirements. Check whether custom fieldtype handlers are registered by the package or expected to exist on the target. Confirm behavior against a fresh, empty v3 install rather than an existing one — a pre-populated target muddies every subsequent diff.
Sequencing.
php please stache:clear before concluding anything is broken or working.content/, users/, resources/blueprints/, resources/fieldsets/ before every non-trivial run.require-dev on a preserved tag purely for auditability.Order content by dependency, not by convenience: users and roles first, then taxonomies, then assets, then entries. If the tool's internal ordering is fixed, verify it matches — a reference migrated before its target is a broken link you will find on a rendered page later, not in a log.
Maintenance — near zero, by design, if you use it as intended. One run, verification, done. The only maintenance burden is the delta window and whatever patches you carry. Keeping it out of require removes it from dependency churn entirely. The permanent-tax failure mode appears only if you adopt the schema-migrations reading: then Control Panel structural edits silently desynchronize the migration files, and the cost compounds for years. Decide in writing and stick to it.
Support. First-party, no SLA, effectively no public validation. Escalate through your Statamic commercial relationship; expect guidance, not guaranteed fixes. Budget for an internal fork — the package is small enough that forking is a realistic line item rather than a threat. Assign a named owner for the migration branch so the fork doesn't become orphaned code.
Scaling — content volume, not traffic. Runtime and failure windows scale with entries, assets, and files; the constraint is verification throughput, not the tool. On a large asset library, budget for chunking, batch verification, and a human reviewing samples. Plan the schedule around reviewer capacity — that's the real bottleneck in the pilot-to-full-run gate.
Failure modes to plan for.
Ramp-up. Requires someone fluent in blueprints, fieldsets, the Stache, and Laravel console tooling — this is a staffing decision, not a composer require. Realistic allocation: one engineer-day to read the source and produce a credible command-surface map; roughly one engineer-week to map a non-trivial content model and enumerate gaps with workarounds. Debugging discipline is cheap and high-yield: -vvv on every command, one step at a time rather than whole batches, git diff on content/ and resources/ after each step, and a clone of the pre-migration site to diff against. When something looks wrong and the cache is clear, read the emitted YAML directly rather than through the Control Panel.
How can I help you explore Laravel packages today?