Database Migrations
How erxes handles MongoDB schema and data changes during upgrades.
For image selection and rollback planning, see Upgrades. For the databases involved, see Configuration and Background Services.
How migrations work
There is no global migration framework: no migrate up CLI, no version table, no automatic run on deploy. Migrations are standalone TypeScript scripts that each open their own MongoDB connection (reading MONGO_URL, sometimes a domain override like CORE_MONGO_URL), do their work, and call process.exit(). You run them deliberately, per release that needs one. Three kinds exist:
- Plugin-owned scripts: live inside the plugin whose data they change, for example
backend/plugins/operation_api/src/migrations/(migrateTasks.ts,migrateCycle.ts),backend/plugins/frontline_api/src/migrations/(ten scripts), andbackend/plugins/content_api/src/modules/cms/migrations/. They are plain scripts you run withtsxagainst the deployment'sMONGO_URL; there is no registration step. - The consolidated
saas-migrationspackage:backend/saas-migrationsholds one-off data migrations organized per domain (core,content,frontline,operation,posclient,products,sales, plus domains for Enterprise plugins). It includes a unified runner, run.ts, that discovers*.tsfiles under each domain directory and executes each in its ownnode --import tsxchild process (required because the scripts self-invoke and exit).coreruns first, then the rest alphabetically. migrations.jsonat the repository root: an Nx workspace artifact listing code migrations for contributors upgrading Nx packages. It is not a product database mechanism; ignore it for deployment planning.
A migration is only relevant if the release you are moving to includes one. Check the release notes and the saas-migrations directory diff for your version jump; most releases add no migration at all.
Running the consolidated runner
From a machine that can reach the database (a checkout, or the erxes/erxes-next-migrations image published by ci-saas-migrations.yml):
# Preview order, run nothing
tsx backend/saas-migrations/run.ts --list
# Everything, core first; stops on the first failure
tsx backend/saas-migrations/run.ts
# Only some domains, or a single script
tsx backend/saas-migrations/run.ts core frontline
tsx backend/saas-migrations/run.ts sales/migrateSales.ts
# Keep going past failures
tsx backend/saas-migrations/run.ts --continue
Or from backend/saas-migrations: pnpm migrate and pnpm migrate:list. The runner exits non-zero if any script fails.
Backup before anything writes
Dump the application database and its logs database. The logs service writes to <db>_logs (for example erxes_logs; see connectionResolvers.ts) and undo history lives there:
mongodump --uri="mongodb://<user>:<password>@<hosts>/erxes?replicaSet=<rs>&authSource=admin" \
--db=erxes --archive=erxes-<date>.archive.gz --gzip
mongodump --uri="mongodb://<user>:<password>@<hosts>/erxes?replicaSet=<rs>&authSource=admin" \
--db=erxes_logs --archive=erxes-logs-<date>.archive.gz --gzip
Verify a restore on staging before relying on it:
mongorestore --uri="<staging-uri>" --archive=erxes-<date>.archive.gz --gzip \
--nsFrom='erxes.*' --nsTo='erxes_restore.*'
Preserve Redis state too if queued BullMQ work matters to your recovery plan.
Upgrade sequence with migrations
Record and back up
Note the running image digests, take the dumps above, and verify the backup restores.
Check what the release ships
Read
CHANGELOG.mdfor your version jump and diffbackend/saas-migrations/and pluginsrc/migrations/directories between the two tags. If nothing changed, no migration step is needed.Stage it
Restore production data to staging, deploy the candidate image set, run the relevant migration scripts, and exercise login, enabled plugins, automations, and file access.
Run in production
Stop writes or use a maintenance window if the migration rewrites data. Run the scripts, then deploy the new image set together; do not mix a new Core API with old plugin APIs unless the release notes allow it. Watch the gateway, Core API, plugin, and logs-service output for migration or composition errors.
Verify
Check
/health,/graphql, owner login, and one write per enabled domain. Keep the pre-upgrade backup until the new version is confirmed.
Migrations are not reversible by redeploying
Rolling the containers back to the previous image does not undo data changes a migration already wrote. Rollback after a data migration means restoring the pre-upgrade backup and losing every write since. Treat migration scripts as one-way and test them in staging first.