Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Migrations in client projects

For agencies and integrators who build and maintain many client sites - shipping changes as migrations in a site or in your own extension, environments per client, a handover the client can read in git, estimating the…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/integrators/migrations-in-client-projects.md

On this page

Migrations in client projects

This page is for agencies and integrators who build Exponential sites for clients and keep them running. Since 6.0.15 the changes you make to a client's database, content and settings can travel as migrations: written once, tested on your development copy, applied in the same order on the client's staging and production, and recorded in git where the client can see them.

What changes for your projects

Before 6.0.15With migrations
a list of steps in a ticket, clicked through on each environmenta file per change, in the project's repository
"did we run that on production?"exp:migration:status on each environment, and migrations/status/<environment>.json in git
an update script that someone ran twicethe record: a migration runs once per installation
a backup taken by hand, maybea caption before every run, restored after a failure
changes repeated for every client by handmigrations in your own extension, applied on every client site that activates it

Two places for a migration

WhereSourceNamespace from --skeletonUse for
the site's migrations/siteSite\Migrationschanges for this one client
extension/<name>/migrations/ of your extensionextension:<name>Extension\<Name>\Migrationschanges every client of that extension gets
./console exp:migration:generate --skeleton news_archive_folder --apply
./console exp:migration:generate --skeleton widget_table --source=extension:acmewidgets --apply

An extension's migrations are found only while the extension is active. A site migration that builds on one names it in its header: requires: 20261101090000_widget_table or requires: extension:acmewidgets. When the change is one every installation of the extension needs on upgrade, whether or not a site chose it, ship an upgrade step instead (Upgrade step or migration?).

Environments per client

Each installation names its environment in site.ini [AdminEnvironment] Level (development, test, staging, production, or auto with EXP_ENV). A migration header can limit a migration:

// environments: staging, production
// environments: !development

Seed data for your development copies, test users, demo content: give those migrations environments: development. Per-environment migrations has the details.

Imports keyed by remote id

Client sites differ in their object and node ids. Find everything by remote id or identifier, and give everything a migration creates a remote id of your own (acme-news-folder). The same rule makes imports repeatable: Idempotent imports keyed by remote id. A migration written this way runs on every client's installation and can meet a half-done state after a failure.

Handover

After every run the status file and the run log are committed, tagged migrations/<environment>/<run-id> and pushed. At handover the client gets, in the repository they own:

  • migrations/: every change, with its description and author in the header;
  • migrations/status/<environment>.json: what each environment has applied;
  • migrations/runs/: the log of every run;
  • the tags: one per run, never moved.

Set [RepositorySettings] Remote to the client's repository, and give the system user of each installation the push credentials (a deploy key). Hand over the policies: who has migration/run and migration/rollback in the client's administration (Policies, views and events).

Estimating

WorkWhat to count
writingone migration per change; schema and content apart; plan(), up(), detect(), down()
testingexp:migration:check in CI; a simulation on SQLite or PostgreSQL; a test of up(), down(), up()
applyinga dry run and a run per environment; on MySQL/MariaDB the time of a caption (a database dump)
large changesbatches and resume for many objects (Large data migrations)

Client-project checklist

  • To do: The record tables exist on every environment (6.0.15-migration-tables is done in exp:upgrade:status).
  • To do: Each installation names its environment; RunAsUser is an existing administrator login.
  • To do: git_manager is active and the remote takes pushes from each installation; migrationpush is scheduled.
  • To do: CI runs ./console exp:migration:check on every pull request.
  • To do: Every migration finds things by remote id or identifier, and says how it is taken back.
  • To do: Policies: only the people who should run migrations on production have migration/run.
  • To do: Disk space for captions is agreed with the host.

Go-live

  1. Freeze the migrations that go live; exp:migration:check passes.
  2. On staging, restored from a copy of production: exp:migration:migrate, then --apply; check the site.
  3. On production: deploy the code, ./console exp:migration:migrate --apply, deploy the caches (Deploying with migrations).
  4. ./console exp:migration:status --fail-on-pending exits 0; the push went through.
  5. Add the run's tag to the release notes for the client.

Moving a client's whole site from another system or another host is not a migration in this sense: Migrations versus migrating a site.

Where to go next

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x