statamic/importer
Statamic Importer brings external data into Statamic collections from CSV, JSON, XML, and other sources. Map fields, transform values, preview results, and run repeatable imports from the control panel or CLI.
Architecture fit. Statamic Importer is a first-party addon that plugs into the CMS's own content model rather than running alongside it. Importer definitions are PHP classes living in the application repo, registered through the published config, mapping a source (CSV, JSON, XML, Eloquent) onto a collection destination with per-field transforms. That makes import logic a versioned, reviewable artifact instead of an ad-hoc script — the single most important property for a migration that has to be re-run, audited, and eventually handed to someone else.
The scope is deliberately narrow: one-directional landing of external rows into entries. It is not a sync engine, and any requirement that looks like CDC, two-way reconciliation, or cross-entry computed fields is out of remit and should be scoped as custom code, not stretched configuration.
Integration feasibility. Install is a single composer require statamic/importer:^2.3.2 plus vendor:publish. The real work is upstream of the package: the target collection and blueprint must already exist as file-based definitions, and every field referenced in a mapping must already be defined on the blueprint. The importer does not create field definitions. Driver breadth (csv, json, xml, eloquent) covers the usual migration shapes; the Eloquent driver is the decision-relevant one because it removes the export-to-CSV intermediate step and lets a parallel-run period read straight from the legacy database.
Technical risk. Three risks dominate, in order:
Importer class and artisan list output over any published example, including our own onboarding notes.Secondary risks: CSV type coercion (empty string is not null), slug collisions, fieldtype-specific payload shapes (Bard/Replicator/Assets need structured JSON, not raw HTML strings), and staleness of search indexes, Stache and static caches after a write.
Key questions to close before committing a date:
Stack fit. The package targets Statamic 4/5 on Laravel 10/11/12 with PHP 8.1+. It installs into the existing application — there is no sidecar service, no separate deployment unit, and no new operational surface beyond the queue that already exists. That is a meaningful procurement advantage: it can be adopted incrementally without an architectural commitment.
Migration path. Sequence it as discovery, not as build:
^2.3.2 and confirm the exact Statamic/Laravel/PHP matrix against the addon's composer.json before investing build time.Compatibility and upgrade handling. Treat 2.3.2 as a data event, not a dependency bump. On any project already carrying Eloquent-sourced relations, the sequence is: drain the queue, deploy, re-import affected content under the same idempotent key, and diff relations before and after. Retire any manual post-import patch script deliberately and in the same window — leaving both the workaround and the fixed resolution logic running double-applies corrections.
Sequencing constraints. Anything order-dependent needs two passes: categories before products, authors before articles, parents before children. Statamic entries fields require the target entry to exist; a forward reference writes null silently. Run parents, verify, then children. Relations should resolve through a map preloaded once before the import and closed over in the transform, never a per-row lookup.
Exit and reversibility. Because the importers are config-as-code and re-runnable, the cost of leaving Statamic later is bounded. Worth stating explicitly whenever lock-in comes up: the same artifacts that make migration in cheap make migration out cheap.
Maintenance. Budget for internal ownership from day one. Importer classes should be reviewed in PRs like migrations, named for the source system, and parameterised on source path or model rather than the file someone happened to import. Each one needs a fixture test asserting field values and relation IDs. The thin dependency graph means no upstream community to lean on when something breaks — the vendor source is the reference, and the plan should assume an engineer reads it.
Support model. The CP pass in the integration plan is the gate: if content ops can drive upload → preview → map → run and interpret the error reporting, they own routine imports and the app team owns definitions. If not, the app team owns every run and that cost recurs on each content cycle. Decide this explicitly rather than discovering it after launch.
Scaling. Imports dispatch as queued jobs. Constraints that matter at volume: worker --timeout and memory_limit sized to the largest batch; explicit column selection on Eloquent sources (a wide legacy table with * will exhaust memory on a chunked run); transforms kept free of database or HTTP lookups, which turn a four-minute import into a forty-minute one through N+1 access. Don't run a large import from the CP on a shared queue without knowing which worker picks it up.
Failure modes to instrument and put in the runbook:
"1"/"true"/"Yes", numbers with thousands separators.Ramp-up and cost. Roughly 1–2 developer days for a first non-trivial importer with relations, plus a validation pass with content ops, plus a half-day fieldtype spike against the real blueprint. Marginal cost per additional source shape is low once the pattern and tests exist. The business case should be priced against the lifetime cost of the in-house Artisan command alternative — every legacy schema or content-model change — not against that script's first version. The same logic applies to roadmap: content import sits on the critical path to relaunch, so any spike it needs belongs in the plan before design freeze, not discovered during build.
How can I help you explore Laravel packages today?