Upgrading
Safe upgrade guidance for MatrixEasyMode in an operator-managed environment.
MatrixEasyMode upgrades should be treated as an operator task, not an automatic background action.
For normal runtime management, see Operations Guide. For environment review before changes, see Configuration.
This guide explains how to upgrade MatrixEasyMode safely in the current operator-managed deployment model.
MatrixEasyMode is currently documented for serious self-hosters and infrastructure-capable operators. That means upgrades should be deliberate, visible, and easy to understand.
The goal is straightforward:
- understand what you are changing
- update the correct layer
- restart in a controlled order
- verify the result before considering the upgrade complete
What this guide covers
This page is about upgrading an existing MatrixEasyMode deployment.
That includes:
- updating the application layer to a newer image version
- rebuilding and restarting local-mode application images
- reviewing
.envchanges when a release introduces new settings - verifying the deployment after the upgrade
- understanding what should not be treated as a routine app upgrade
If you are deploying for the first time, start with:
Upgrade posture
A good MatrixEasyMode upgrade is:
- intentional
- version-aware
- reversible in practice
- verified with status checks and logs
A bad MatrixEasyMode upgrade is:
- changing multiple layers at once without a plan
- editing
.envcasually without review - upgrading infrastructure and application services together without understanding the blast radius
- assuming that “containers are running” means the upgrade succeeded
Understand the deployment layers
MatrixEasyMode uses a staged deployment model:
- infrastructure first
- PostgreSQL
- Nginx Proxy Manager
- application second
- MatrixEasyMode API
- MatrixEasyMode web frontend
For normal operator upgrades, the safest default is to upgrade the application layer only.
That means:
- update the MatrixEasyMode app images
- recreate the app containers
- leave PostgreSQL and Nginx Proxy Manager alone unless you are intentionally performing infrastructure maintenance
Before you upgrade
Before changing anything, do these checks.
1. Review current state
./stack.sh status2. Review current app logs
./stack.sh logs appYou want a reasonably understood baseline before you upgrade.
3. Review your environment file
cat .envPay particular attention to:
MEM_IMAGE_SOURCEMEM_VERSIONMEM_REGISTRYMEM_API_IMAGEMEM_WEB_IMAGENEXTAUTH_URLNEXT_PUBLIC_API_URLNPM_BASEURLINGRESS_CERTIFICATE_NAME
4. Read the release notes first
Before moving to a newer version, check the release notes for:
- new required environment variables
- renamed settings
- changed runtime assumptions
- migration notes
- upgrade warnings
If a release adds new required configuration and you skip that review, the upgrade can fail in ways that look like runtime defects when the real issue is configuration drift.
Backup and recovery posture
MatrixEasyMode is operator software. You are expected to think about recovery before change.
Before any meaningful upgrade, make sure you understand:
- where your PostgreSQL data lives
- how you would restore it if needed
- whether you need a backup before the change window
- whether your current
.envis preserved somewhere safe
At minimum, treat these as sensitive operator assets:
.env- PostgreSQL data
- any operator-managed reverse proxy or certificate state that matters to your environment
This guide does not prescribe one backup product or workflow, but it does strongly recommend that you do not treat upgrades as disposable if the environment matters to you.
The normal upgrade path
For most operators, the upgrade path should be:
- read the release notes
- review
.env - update the target application version
- recreate the application layer
- verify status and logs
- verify browser access and public routes
Upgrading in registry mode
Registry mode is the standard path for released images.
Typical relevant values are:
MEM_IMAGE_SOURCE=registry
MEM_REGISTRY=ghcr.io/matrix-easy-mode
MEM_VERSION=0.1.0Step 1: choose the target version
Update the version in .env.
Example:
MEM_VERSION=0.2.0Pinned versions are preferred over latest for serious operator-managed deployments.
Step 2: update the app layer
Use the helper script:
./stack.sh update appThis is the intended application-layer update path.
Step 3: verify the running state
./stack.sh status
./stack.sh logs appStep 4: verify public access
Confirm that the main routes still behave correctly for your environment, for example:
https://admin.your-domain.comhttps://api.your-domain.com
Check for:
- successful frontend load
- expected API reachability
- no repeated ingress bootstrap errors
- no obvious auth callback failures
Upgrading in local mode
Local mode is intended for contributors and internal development-style workflows.
Typical relevant values are:
MEM_IMAGE_SOURCE=local
MEM_API_IMAGE=mem-api:local
MEM_WEB_IMAGE=mem-web:localIn local mode, “upgrading” usually means rebuilding the current application images from newer local source code rather than pulling published tags.
Step 1: update your local source checkouts
Update the local MatrixEasyMode application repositories you use as build contexts.
Exactly how you do that depends on your local repository layout and workflow.
Step 2: confirm the local build contexts still match reality
Review:
docker-compose.local.ymlMake sure the referenced source paths still point to the repositories you actually intend to build.
Step 3: rebuild the application images
./stack.sh build appStep 4: restart the application layer
./stack.sh restart appOr, if needed:
./stack.sh down app
./stack.sh up appStep 5: verify state and logs
./stack.sh status
./stack.sh logs appWhen .env needs to change
Not every upgrade is image-only.
Sometimes a newer MatrixEasyMode release may introduce:
- a new environment variable
- a changed default
- a renamed setting
- a new feature flag
- a new image-related expectation
In those cases:
- compare your current
.envwith the updated.env.exampleor release notes - add or adjust only the values that are actually required
- review the final file before restarting services
Be careful not to overwrite your working secrets casually while copying new examples forward.
Safe upgrade workflow
A good practical workflow looks like this.
Registry mode
./stack.sh status
cat .env
# update MEM_VERSION
./stack.sh update app
./stack.sh status
./stack.sh logs appLocal mode
./stack.sh status
cat .env
# update local source checkouts if needed
./stack.sh build app
./stack.sh restart app
./stack.sh status
./stack.sh logs appVerifying an upgrade
An upgrade is not complete just because the containers restarted.
Verify these areas explicitly.
Runtime state
./stack.sh statusApplication logs
./stack.sh logs appYou are looking for repeated failures such as:
- configuration binding errors
- NPM authentication failures
- ingress bootstrap retry loops
- API startup failures
- web runtime or auth errors
Public routes
Confirm that your expected public routes still work.
Typical examples:
https://admin.your-domain.comhttps://api.your-domain.com
Authentication path
If your environment uses the normal web login flow, verify that login and session behavior still work after the upgrade.
Ingress assumptions
Confirm that:
- Nginx Proxy Manager is still reachable
- the wildcard certificate still exists
INGRESS_CERTIFICATE_NAMEstill matches reality- the public URLs in
.envstill match the actual deployed hosts
What not to treat as a routine app upgrade
These are different kinds of changes and should be handled more carefully:
- PostgreSQL major version changes
- Nginx Proxy Manager version changes
- moving persistent data paths
- changing public hostnames
- changing certificate naming strategy
- changing the local source layout in a rushed or undocumented way
Those are operational changes, not just “upgrade the app” changes.
Manual Docker Compose upgrade flow
Advanced operators may prefer raw Docker Compose commands.
Registry mode
Pull updated images and recreate the app layer:
docker compose --profile app pull api web
docker compose --profile app up -d api webCheck state:
docker compose --profile app ps
docker compose --profile app logs -f api webLocal mode
Rebuild and recreate the app layer:
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app build api web
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app up -d api webCheck state:
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app ps
docker compose -f docker-compose.yml -f docker-compose.local.yml --profile app logs -f api webThe script-first workflow is still preferred unless you specifically need direct Compose control.
If the upgrade goes wrong
Use this sequence.
1. Check status
./stack.sh status2. Inspect app logs
./stack.sh logs app3. Review .env
cat .env4. Confirm mode-specific assumptions
For registry mode, confirm:
MEM_VERSIONis what you intended- the registry and image tags are valid
For local mode, confirm:
- the new images actually built
- the tags match
.env docker-compose.local.ymlstill points to valid source paths
5. Confirm ingress assumptions
Make sure:
- NPM is reachable
- credentials still work
- the wildcard certificate still exists
- public URLs and DNS still match the deployment
If needed, use the broader guidance in Troubleshooting.
Rollback mindset
If you operate MatrixEasyMode seriously, you should think about rollback before you need it.
A practical rollback posture usually means:
- you know the previous working application version
- you have preserved the prior
.env - you understand whether database changes or config changes make rollback more complicated
- you do not upgrade blindly in environments you care about
For registry mode, rollback may be as simple as restoring the previous MEM_VERSION and recreating the app layer.
For local mode, rollback usually means rebuilding from the previous working source state and restarting the app layer.
Recommended operator habits
Good habits during upgrades include:
- pinning versions instead of relying on
latest - changing one layer at a time
- checking release notes before changing
.env - reading logs after every upgrade
- verifying public behavior, not just container state
- keeping infrastructure upgrades separate from app upgrades
