RememberStackremember.dev/docs

Upgrades and migrations

A self-hosted deployment is yours to upgrade and to back up. This page covers how releases are published, what happens to the database on an upgrade, the order to do it in, and how to take a backup you can restore.

Releases and image tags

Each release has a Git tag (v0.17.0) and an image with the same version number and no v: ghcr.io/writeitai/remember-stack:0.17.0. There is no latest tag. The release on GitHub attaches the compose.yaml and .env.example for that version (the second downloads as default.env.example) and openapi.json.

compose.yaml names the image tag, so the version you run is the version of the compose.yaml you start. The client package on PyPI, remember, is released from the same tag with the same version number.

What setup does on an upgrade

The setup service runs before the API and workers every time you run docker compose up. It:

  1. applies every database migration the new release brings (alembic upgrade head);
  2. checks that the deployment id, slug and name still match the database;
  3. installs any assured operations and example saved queries the release adds;
  4. checks that the embedding model still matches the stored vectors, then re-publishes the search channels, rebuilding entity profile vectors when needed.

The API and the workers start only after setup exits successfully. If a migration fails, setup exits with an error, nothing else starts, and docker compose logs setup shows why.

Migrations only go forward. Some refuse to convert data in a way that would lose it, and there is no supported downgrade. To go back to an earlier release, restore a backup taken before the upgrade.

Upgrading does not reprocess documents already in the memory. They keep what the earlier release extracted from them; new documents are processed by the new code.

Upgrade step by step

  1. Read the release notes on GitHub for the version you are moving to.

  2. Back up, as described below.

  3. Get the new files:

    git fetch --tags
    git checkout v<new-version>
    diff .env .env.example

    Add any new required variable to your .env. Keep your deployment id, slug and name as they are.

  4. Stop the old processes, so no old worker runs against a database that is being migrated:

    docker compose down

    down removes the containers and keeps the volumes, and with them the memory.

  5. Get the new images:

    docker compose pull api postgres

    All app services share the image pull api fetches. Each release also publishes its own PostgreSQL image, so postgres is pulled too.

  6. Start:

    docker compose up -d --wait
    docker compose logs setup
    curl http://localhost:8000/deployment

    build_revision in /deployment names the source commit of the image now serving.

PostgreSQL prerelease versions

RememberStack runs on a PostgreSQL 19 beta (19beta3 at v0.17.0). A PostgreSQL prerelease does not promise that its data directory opens under the next prerelease or the final release. The project has not published a procedure for moving a deployment's data across such a change.

If a release changes the PostgreSQL image, its release notes are the place to look. Without instructions there, move the data with a logical dump and restore (below) into a new PostgreSQL volume, or start a new deployment and send your documents again.

The deployment id is permanent

REMEMBERSTACK_SELFHOST_DEPLOYMENT_ID names the deployment: its trust domain. Every token is bound to it, and every stored row belongs to it. The install step generates it once, and the first setup records it.

A database holds exactly one deployment. If the id in .env differs from the recorded one, setup refuses to start and names the recorded id, so the API and workers do not start either. Restore the recorded value. The same check covers the slug, the name, the default language and the bucket names: setup names the ones that changed. Change none of them after the first start.

To start over under a new id, remove the volumes (docker compose down --volumes) and send your documents again.

Back up

Backups are your responsibility. RememberStack does not schedule them, and the project does not test a restore procedure. What follows is grounded in how the Compose deployment stores its data.

A deployment's state lives in four Docker volumes:

VolumeMust be backed up
rememberstack_postgres-dataYes: the database
rememberstack_object-store-dataYes: original files and derived artifacts
rememberstack_forget-manifestsYes, with the others: hard-forget manifests
rememberstack_app-stateOptional: working directories and debug captures

Filesystem-view snapshots in the object store can be rebuilt; everything else in the first three volumes cannot. The database and the object store refer to each other, so back them up at the same moment.

A cold backup of the volumes

The simplest consistent backup stops the stack and copies the volumes:

docker compose stop
mkdir -p backup
for volume in postgres-data object-store-data forget-manifests app-state; do
  docker run --rm \
    -v "rememberstack_${volume}:/source:ro" \
    -v "$PWD/backup:/backup" \
    alpine tar -czf "/backup/${volume}.tar.gz" -C /source .
done
docker compose start

Keep the backup/ directory and your .env together: a restore needs the same deployment id and the same database and object-store credentials.

To restore it into an empty stack on the same or another machine, with the same .env:

docker compose down -v          # deletes the current volumes
docker compose create           # creates empty volumes and containers
for volume in postgres-data object-store-data forget-manifests app-state; do
  docker run --rm \
    -v "rememberstack_${volume}:/target" \
    -v "$PWD/backup:/backup:ro" \
    alpine tar -xzf "/backup/${volume}.tar.gz" -C /target
done
docker compose up -d --wait
docker compose exec -T api remember ops graph-catalog ensure

The last command checks that the graph definitions in the restored database match this release (Operating the pipeline).

A logical backup

pg_dump backs up the database while it runs:

docker compose exec -T postgres \
  pg_dump -U rememberstack -d rememberstack --format=custom > rememberstack.dump
docker compose exec -T postgres \
  pg_dumpall -U rememberstack --roles-only > roles.sql

Use your own user and database names from .env. The second file matters: the migrations create a separate, restricted PostgreSQL role for SQL queries, and roles are not part of pg_dump. Copy the object-store buckets (remember-raw, remember-artifacts, remember-corpusfs) at the same time with an S3 tool such as rclone sync. Restoring a logical backup means creating the roles, restoring the dump into an empty database with pg_restore, copying the buckets back, and running setup; the project has not tested this path.

Hard-forget manifests

The forget-manifests volume holds the list of documents that were permanently removed, so a restore can remove them again from an older backup. A deployment started from compose.yaml has no command that creates such manifests. If the volume does hold manifests for your deployment, the API refuses to start: honouring them needs a recovery procedure the Compose deployment does not include.