Upgrade procedure
Upgrade procedure
Section titled “Upgrade procedure”This is the supported flow for moving an installation from one tagged release to the next. The flow assumes:
- The customer is on the Customer Onboarding layout (or the Manual install (advanced) equivalent).
- The current install is healthy —
/healthreturns{ok:true}for all four services before starting. - There is a recent backup (see Backup & Restore). The pre-upgrade snapshot in step 1 below is mandatory regardless.
If your install was set up via Docker Compose, the same logic applies — substitute docker compose pull && docker compose up -d for the manual pm2 reload all step.
Semver policy (what each version bump means)
Section titled “Semver policy (what each version bump means)”ecommus follows semver across both the framework and the public plugin/theme contracts:
| Bump | What changes | Customer action |
|---|---|---|
| Patch | Bug fixes, security patches, internal refactors. No public-API changes. | Upgrade any time. No code changes on customer side. |
| Minor | New features, additive plugin/theme contract additions, deprecations. | Read the release notes for new opt-in features and deprecations to migrate off of. |
| Major | Breaking plugin / theme / route / config contract changes. | Read the migration guide for that release before bumping. Test in staging first. |
Stable surfaces (semver-protected — no breaking changes within a major):
@ecommus/plugin-sdktypes +PluginContextshape@ecommus/theme-sdkmanifest schema + slot map@ecommus/clientREST client method signatures- License JWT shape (
packages/core/src/license.ts) - Public REST routes (
/api/admin/*,/api/storefront/*,/api/super-admin/*) - Webhook payload shapes for issued events
Internal surfaces (no semver guarantee — may change in any release):
- Service helpers under
apps/api/src/services/ - Drizzle schema details (always go through the migration runner, never read tables directly from outside
apps/api) - Internal events not exposed via the EventBus public types
1. Pre-upgrade checklist
Section titled “1. Pre-upgrade checklist”Run all of these in the listed order. Aborting at any step is fine — the install is unchanged until step 4.
# 1.1 Confirm current install is healthycurl https://api.mystore.ro/healthcurl https://admin.mystore.ro/api/healthcurl https://superadmin.mystore.ro/api/health
# 1.2 Check the release notes for the target version# -> https://docs.ecommus.ro/whats-new/# -> https://github.com/MDLABS-cmd/ecommus/releases/tag/<v># If MAJOR: read the migration guide LINKED FROM the release notes# If MINOR: scan the deprecation list
# 1.3 Take a database snapshotpg_dump -Fc ecommus_prod > /backup/pre-upgrade-$(date +%F-%H%M).dump
# 1.4 Capture the current installed plugin set (for diff after upgrade)node --experimental-strip-types apps/api/src/cli/list-plugins.ts > /backup/plugins-pre.txt
# 1.5 Stop the workers gracefully — prevents in-flight jobs landing on# a half-upgraded code+schema combopm2 stop ecommus-api-workers # or: ECOMMUS_WORKERS=false on the running instance
# 1.6 Notify operators (super-admin → settings → maintenance window)The snapshot in 1.3 is the rollback point. Verify it was created (ls -lh it) before proceeding.
2. Pull the new release
Section titled “2. Pull the new release”git fetch --tagsgit checkout v<new-release> # e.g. v1.4.0npm ci # license-bound npm token resolves @ecommus-plugin/* updates tooIf npm ci fails with 403 forbidden on @ecommus-plugin/<x> or @ecommus/theme-<x>:
- Your
NPM_REGISTRY_TOKENis missing or revoked. Re-fetch from your customer portal. - Your license expired. Renew via super-admin or contact your account manager.
- The plugin is no longer on your license. Either re-issue the JWT or stay on the previous release.
3. Build all four apps
Section titled “3. Build all four apps”npm --workspace @ecommus/storefront-astro run buildnpm --workspace @ecommus/admin run buildnpm --workspace @ecommus/super-admin run buildnpm --workspace @ecommus/api run buildIf any build fails, git checkout v<previous-release> and npm ci to revert. Builds are idempotent — re-running is safe.
4. Run migrations
Section titled “4. Run migrations”Migrations run before the new code is live. Two phases:
# Core framework migrations (apps/api owns these)node --experimental-strip-types packages/db/src/migrate.ts
# Plugin migrations (collected by each plugin via ctx.registerMigration())node --experimental-strip-types apps/api/src/cli/run-plugin-migrations.tsBoth runners are idempotent. They write to _ecommus_core_migrations / _ecommus_plugin_migrations and skip already-applied entries. A failed plugin migration logs the failure and continues — fault-tolerant per CLAUDE.md §0.4.
If any migration fails:
- Don’t reload pm2. The old code still runs against the partially-upgraded DB.
pg_restorethe snapshot from step 1.3 (see Backup & Restore for the procedure).- File a bug with the failing migration name + log excerpt.
5. Reload the services
Section titled “5. Reload the services”pm2 reload allpm2 reload is graceful — in-flight requests finish on the old process before the new one takes over. There’s no observable downtime under normal load.
If the install is single-process (no pm2 cluster mode), use pm2 restart all instead — there’s a brief 1-2 second outage. Acceptable for non-customer-facing maintenance windows.
6. Re-enable workers + smoke test
Section titled “6. Re-enable workers + smoke test”# 6.1 Re-enable workerspm2 start ecommus-api-workers # or: ECOMMUS_WORKERS=true and pm2 restart api
# 6.2 Healthcurl https://api.mystore.ro/healthcurl https://admin.mystore.ro/api/healthcurl https://superadmin.mystore.ro/api/health
# 6.3 Plugin sanitynode --experimental-strip-types apps/api/src/cli/list-plugins.ts > /tmp/plugins-post.txtdiff /backup/plugins-pre.txt /tmp/plugins-post.txt # expect: only version bumps
# 6.4 Hit one admin route end-to-end (forces a tenant-scoped query)curl -H "Authorization: Bearer <admin-jwt>" https://api.mystore.ro/api/admin/products?limit=1
# 6.5 Hit one storefront route (forces a host-resolved tenant)curl https://mystore.ro/api/storefront/categoriesIf anything is off, see Rollback below.
7. Post-upgrade
Section titled “7. Post-upgrade”- Read the release notes for any manual post-upgrade steps (e.g. “rotate
JWT_KEY_ID”, “re-import niche-package preset”). - Acknowledge the maintenance window in super-admin.
- If the upgrade introduced new env vars, add them now and
pm2 restart api(re-read of.env). - For major-version upgrades, monitor error rates for the next 24 h via the observability stack (
SENTRY_DSN+ Prometheus).
Rollback
Section titled “Rollback”Use the snapshot from step 1.3.
# 1. Stop the appspm2 stop all
# 2. Restore the DBpg_restore --clean --if-exists --no-owner --dbname=ecommus_prod \ /backup/pre-upgrade-<timestamp>.dump
# 3. Check out the previous releasegit checkout v<previous-release>npm ci
# 4. Re-buildnpm --workspace @ecommus/storefront-astro run buildnpm --workspace @ecommus/admin run buildnpm --workspace @ecommus/super-admin run buildnpm --workspace @ecommus/api run build
# 5. Startpm2 start all
# 6. Verifycurl https://api.mystore.ro/healthRollback is destructive on the data side — any rows written between the snapshot and the rollback are lost. Avoid running rollback on a live store unless the alternative is worse (data corruption, security exposure).
Breaking-change handling (major bumps)
Section titled “Breaking-change handling (major bumps)”When the release is a major bump:
- Test in staging first. Stand up a staging install pointed at a snapshot of prod, run the full upgrade flow, run the smoke tests. Only then promote to prod.
- Read the migration guide linked from the release notes. Major releases ship a
MIGRATION-Vx-to-Vy.mddoc per release in/docs/08-changelog/. - Audit your custom plugins. If your store carries internal plugins (i.e. not from
npm.ecommus.cloud), the plugin contract may have changed. The migration guide lists every removed export, renamed type, and signature change. - Audit your theme overrides. Theme slot maps may have new required slots or removed deprecated ones.
If the framework wants you to drop a deprecated config key (e.g. legacy JWT_SECRET removed in v2.0), the migration guide lists the new equivalent and the boot-time fail-fast that catches the omission.
See also
Section titled “See also”- Backup & Restore — RPO/RTO, off-site target, restore drill
- Customer Onboarding — initial provisioning playbook
- Manual install (advanced) — manual setup reference
- Environment Variables — full env reference
- What’s New — recent release notes