Migrating from Adobe Commerce Cloud or Platform.sh¶
If you already ship Magento on Adobe Commerce Cloud (ACC) or Platform.sh / Upsun, MageLift should feel familiar at the edges and different in the middle. You still declare environments in YAML, promote an immutable build, and use CLI verbs for logs and shells. The cloud account, network, and managed services are yours. MageLift does not rent a PaaS for you.
Certified paths today: AWS ECS Fargate and the evidenced GCP GKE Autopilot
cells. AWS EKS, GCP GKE Standard, OVH MKS, and Scaleway Kapsule stay
experimental. Import maps allowlisted Magento configuration into
application.magento, including an admin front name, cookie domain, CORS origins,
and consumer mode or names when the source provides them. It does not invent
websites, stores, or store views.
Mental model¶
| ACC / Platform.sh idea | MageLift equivalent |
|---|---|
.magento.app.yaml / .platform.app.yaml |
magelift.yaml (portable Magento inputs) |
| Environment branches / multi-env | environments.* overlays with inheritance |
| Variables / secrets | Secret references (aws-secrets-manager://…), never plaintext |
| Build + deploy hooks | Build pipeline + post-deploy Magento phases |
magento-cloud / platform SSH |
magelift exec / magelift ssh (ECS Exec into web or cron) |
| Environment logs | magelift logs --service web\|deploy\|cron |
| Cron workers | ECS cron service + magelift cron-run |
| Local Lando / Docker | magelift local Compose loop (account-free) |
What stays the same¶
- One config file in the Magento repo drives environments.
- Builds produce a digest you promote; you do not rebuild for production.
- Day-2 ops are CLI-first: health, logs, exec, cache flush, reindex.
- Preview / staging / production are first-class environment classes.
What changes on purpose¶
- You own the AWS account. Billing, IAM, DNS, and KMS keys are yours. Bootstrap creates the shared control-plane pieces; stacks stay in that account.
- Topology is not YAML soup. Network CIDRs, RDS vs experimental Aurora,
OpenSearch mode, and NAT mode are explicit escape hatches on
target.aws, not hidden SKU swaps. Standard/HA YAML that omitsqueueModedefaults toecs-rabbitmq; explicitamazon-mqremains experimental-warn. Certified queue cells aredbandecs-rabbitmq. - No inbound SSH.
magelift sshis ECS Exec. There is no bastion and nomagelift tunnelon the Fargate path. - Deploy is not a shell service. Migrations run as a one-off candidate ECS
task. Use
magelift logs --service deployfor migrate output.execonly attaches to long-livedweborcrontasks. - Build cannot differ per environment. Artifacts are immutable; environment overlays change runtime config and capacity, not the image.
Side-by-side: ACC app YAML → MageLift¶
ACC / Upsun style (illustrative):
# .magento.app.yaml (shape only; do not paste into MageLift)
name: app
type: php:8.3
hooks:
build: |
set -e
composer install
deploy: |
php bin/magento setup:upgrade
relationships:
database: "mysql:mysql"
redis: "redis:redis"
rabbitmq: "rabbitmq:rabbitmq"
MageLift equivalent (portable inputs + AWS catalog escape hatches):
schemaVersion: 1
project:
name: app
application:
edition: open-source
version: 2.4.9
mode: integrated
build:
php: "8.5"
extensions: [apcu, bcmath, ftp, gd, intl, mbstring, opcache, pdo_mysql, redis, soap, sockets, sodium, xsl, zip]
composer:
version: "2.10"
credentials: aws-secrets-manager://magelift/composer
target:
provider: aws
runtime: ecs-fargate
aws:
catalog:
queueMode: ecs-rabbitmq # or amazon-mq | db
defaults:
region: eu-west-3
preset: preview
environments:
staging:
account: "123456789012"
branches: [main]
domain: staging.example.com
Hooks stay typed Magento/build phases, not free-form shell strings in portable YAML.
Variables become secret references. Topology (Aurora vs RDS, queue mode, NAT) lives
under target.aws, not as PaaS relationship aliases.
Generate YAML from ACC / Upsun (shipped)¶
Offline importers generate reviewable MageLift YAML. They never accept foreign
PaaS schemas as deploy input: magelift --config .magento.app.yaml … fails because
config.Load requires schemaVersion: 1.
From the Magento project root (where .magento.app.yaml or .platform.app.yaml lives):
# Adobe Commerce Cloud → magelift.yaml (refuse if the path already exists)
magelift init --from-acc
# Upsun / Platform.sh
magelift init --from-upsun
# Overwrite an existing file only with explicit confirmation
magelift init --from-acc --yes
# Write a review copy without touching the default --config path
magelift init --from-acc --config-out review.magelift.yaml
--from-acc and --from-upsun are mutually exclusive. The mapper covers structural
app/services/routes/cron plus the frozen D-07 env allowlist (crypt → encryption
secret ref placeholder; UPDATE_URLS/routes → domain; DB/Redis/OpenSearch/AMQP
relationships → capability / catalog intent; SCD_* → build.staticContent; and
allowlisted CONFIG__DEFAULT__* values → Magento admin, cookie, CORS, and consumer
overlays). See ece-tools parity.
The importer also carries ACC and Upsun PHP runtime.extensions into
build.extensions, and the composer/composer PHP dependency into
build.composer.version. The isolated builder checks both values before it runs
Magento lifecycle steps. Unsupported PaaS settings remain in the unmapped sidecar.
When any key is outside that allowlist, MageLift still writes the YAML, writes a
sidecar next to the output path (magelift.unmapped.md, or
<stem>.unmapped.md when using --config-out), and exits non-zero. Fix or accept
the residuals by hand before deploy.
Fastly migration intent¶
If the source service file declares a Fastly service, the importer writes an
edge.externalProvider: fastly intent and keeps the route hostname as an edge domain.
It never copies a Fastly token, private key, or VCL body. The unmapped sidecar
names the missing serviceId and tokenSecret fields so an operator can add a
secret reference deliberately:
edge:
externalProvider: fastly
serviceId: "123456"
tokenSecret: aws-secrets-manager://magelift/fastly-api-token
domains: [store.example.com]
tls: true
purgeOnDeploy: true
# Optional reviewed VCL or policy artifact reference.
vclRef: fastly/vcl/store.vcl
Fastly is an experimental migration target in RC1. Use an authenticated Fastly
CLI profile and run magelift edge plan, magelift edge apply, and
magelift edge destroy --yes to manage the declared domains. A normal origin
deployment applies Fastly after its candidate and health gates pass. The
first-party AWS, GCP, OVHcloud, and Scaleway stacks keep origin and edge as
separate capabilities, so a Fastly request cannot silently become CloudFront.
The first Fastly account smoke is recorded in
fastly-adapter-live-2026-08-13.md.
It found that the authenticated account rejects the CLI's classic service-domain
endpoint in favor of Domain Management. A disposable routed-domain test then proved
TLS, active-version attachment, origin routing, purge, and teardown. The adapter
uses the current fastly domain create, domain list, and domain delete
--domain-id commands, reuses domains whose description matches the exact
MageLift marker, and stores only ownership IDs in mode-0600 local state. Existing
Fastly services are preserved unless the adapter created them. The live adapter
lifecycle test proves the create, list, purge, and cleanup path, while full
production edge certification remains open.
Phase 4 ships the config onramp above. Database dump import, media sync, and the cutover runbook below ship in Phase 5. Brownfield attach of an existing AWS VPC / RDS MySQL is Phase 8; see brownfield-attach.md (limits, egress ownership, detach). Multi-cloud / Cloud SQL attach remains later.
- Run
magelift init --from-accor--from-upsun; review YAML + any unmapped sidecar. - Replace encryption / Composer secret placeholders with real Secrets Manager (or SSM) refs.
- Add
preview,staging, andproductionenvironments as needed. - Run
magelift doctorandmagelift bootstrapin a non-production AWS account. - Build and promote one digest; deploy preview with destroy-on-exit acceptance
(
docs/aws-acceptance.md) until destroy leaves zero tagged leftovers. - Follow the cutover runbook below before pointing production DNS at MageLift.
Cutover runbook (dump, media, maintenance, reindex, verification, rollback)¶
This runbook moves a store onto a MageLift-managed environment. Phase 5 proves the executable local half (dump import, media sync, maintenance/reindex/verify/rollback command shapes) offline. Live DNS cutover, a full non-prod rehearsal against a managed cloud instance, and the managed-instance dump-import acceptance cell ride paid follow-up gate; no fourth paid AWS pass in Phase 5.
Prerequisites¶
- Valid
magelift.yamlwith a non-production environment (preview/staging) andseedDumpset viamagelift env create … --dump <path>(or an existing overlay). - Sanitized dump outside git; media tree available as a local directory.
- Deployed environment with stack outputs including
mediaBucket(AWS) and a reachable DB for import. - Day-2 path working:
magelift exec,magelift reindex,magelift logs(operations).
1. Import the database dump¶
First successful deploy with seedDump status recorded auto-imports once (hybrid
D-01). For explicit retries or dry runs of the same path:
# Journal: recorded|failed → importing → imported|failed
magelift env import-dump <environment>
# Retry into a non-empty database (MIGRATE-05 / D-04)
magelift --yes env import-dump <environment>
# Confirm journal
magelift env status <environment> -o json
Do not use magelift local seed for cloud environments; that verb is local Compose only.
2. Sync media into object storage¶
# Merge upload: PutObject only; remote extras kept; fails if source keys missing after list
magelift env media-sync <environment> --source /path/to/media-or-pub
Key mapping: if --source contains pub/media/, keys are relative to that prefix;
otherwise --source is the media root. Offline evidence tier is unit + Floci
listing-diff (see capability matrix); live bucket sync on a
paid account is not claimed by Phase 5.
3. Magento maintenance mode¶
Put Magento into maintenance before DNS or final traffic shift so shoppers do not hit a half-cut store:
magelift exec --env <environment> --service web --container web -- \
bin/magento maintenance:enable
# After verification (or on rollback):
magelift exec --env <environment> --service web --container web -- \
bin/magento maintenance:disable
4. Reindex¶
magelift reindex --env <environment>
# equivalent fixed Magento path via ECS Exec:
# magelift exec --env <environment> --service web --container web -- bin/magento indexer:reindex
Optionally flush caches after reindex: magelift cache-flush --env <environment>.
5. Verification checks¶
Before DNS:
magelift env status <environment> -o json:seedDumpStatusisimported(or intentionally absent if no dump).- Storefront / admin health through the ALB or preview URL (
mageliftruntime health / browser smoke), not only Pulumi success. - Sample SKUs, CMS pages, and a media URL from the synced bucket path.
magelift logs --env <environment> --service web --since 30mfor fatal Magento errors;magelift logs --service deployif a migrate candidate ran.
6. DNS cutover¶
Point the customer domain (and ACM certificate validation, if needed) at the MageLift edge for that environment. DNS TTL, Route53/ACM wiring, and live non-prod rehearsal evidence are paid follow-up gate. Document the planned records here operationally, but do not treat Phase 5 docs or local scratch as SC5 live proof.
Cloudflare preview rehearsal (MIGRATE-04 / Phase 7)¶
Preferred non-prod host: set MAGELIFT_CUTOVER_HOST to an operator-owned
FQDN you control (docs/examples use magelift-preview.example.com). Use an API
token with Zone.DNS Edit (and Zone.Zone Read) via CLOUDFLARE_API_TOKEN or
CF_API_TOKEN. Do not use Wrangler OAuth for DNS writes. Wrangler OAuth is
zone:read only and cannot create/update records.
export CLOUDFLARE_API_TOKEN=... # Zone.DNS Edit; not Wrangler OAuth
export MAGELIFT_CUTOVER_HOST=magelift-preview.example.com # your zone
# Optional: MAGELIFT_CUTOVER_ZONE=example.com when auto-derive is wrong
# Point at stack applicationURL / LB hostname or IPv4 from the paid pass:
TARGET=<ingress-or-lb> ./scripts/cutover-dns-cloudflare.sh
# Rehearse without mutating:
TARGET=example.invalid ./scripts/cutover-dns-cloudflare.sh --dry-run
# Harness EXIT / teardown:
./scripts/cutover-dns-cloudflare.sh --cleanup
Auth and zone notes: use a Cloudflare API token with Zone.DNS Edit on the
preview host zone; see evidence
for a rehearsal that used cf CLI dns_records:edit and --cleanup.
7. Rollback¶
If verification fails after traffic shift:
- Revert DNS to the previous origin (lowest blast radius).
- Disable Magento maintenance on the previous origin if you enabled it there; keep MageLift in maintenance until you decide to retry.
- Infrastructure rollback for a disposable preview:
magelift env destroy <name> --yes(protection must be off) or restore frommageliftstate backup/restore day-2 verbs when the env is long-lived; see operations. - Re-import only with
--yeswhen the target DB is non-empty; prefer a fresh preview env over overwriting production.
Evidence (MIGRATE-04 / SC5)¶
| Slice | Status |
|---|---|
| Runbook + local scratch (dump, media unit/Floci, maintenance/reindex/verify/rollback command shapes) | Phase 5 |
| Live DNS + full non-prod cutover rehearsal + managed-instance dump cell | paid follow-up gate (no Phase 5 paid AWS pass) |
Where to read next¶
- Architecture: product matrix and ports/adapters boundary
- Configuration: field reference for
magelift.yaml - Brownfield attach: existing AWS VPC/RDS adopt + detach
- ece-tools parity: closed vs intentional-gap matrix (D-06 / D-07)
- Operations: logs, exec, CI generate, local
dev - Local AWS acceptance: free-tier-friendly real AWS loop
- Capability matrix: evidence tiers for media / day-2 ports