Skip to main content
Data migration scripts live in backend/scripts/data_migrations/. They handle one-off corrections, backfills, or clean-ups that cannot be expressed as a zero-downtime Alembic migration.
This page covers how to run the scripts. The rationale for each individual migration — the problem it fixes and what it changes, plus any relevant details such as conflict handling or idempotency — lives in the module docstring at the top of the corresponding script in backend/scripts/data_migrations/. Read that before running one.

How they run

Recent migrations are wired into the container startup script (backend/scripts/start/app.sh) and run automatically on every deploy, after Alembic migrations are applied. They are idempotent (no-op once the data is corrected) and non-fatal - a failure logs a warning and retries on the next startup. This automatic execution is temporary. Each entry in app.sh is gated by a TODO: Remove this after ~<date> comment and is deleted once existing deployments have had time to upgrade. After that point the script is no longer invoked on startup. The practical consequence: if you upgrade Open Wearables long after a migration shipped, the corresponding script may already have been removed from app.sh and will not run automatically. In that case, run it manually (see below). Scripts that were never added to app.sh must always be run manually.

Prerequisites

The scripts import from the app package and connect to the database via the environment variables in backend/config/.env. You need:
  • Docker Compose services running (docker compose up -d)
  • The app container healthy (check with docker compose ps)
  • A database with the latest Alembic migrations applied (docker compose exec app uv run alembic upgrade head)

Running a script

All scripts are run inside the app container using uv run:

Dry run first

Every script supports a --dry-run flag. Always run it first — it prints the rows that would be affected without making any changes:

Apply changes

Once satisfied with the dry-run output, run without the flag:
Scripts write directly to the database. There is no automatic rollback. Take a database snapshot before running against production.