How Lightdash versioning works
Lightdash uses semantic versioning,major.minor.patch:
- Patch versions are small fixes.
- Minor versions add features or larger changes that can be backwards incompatible. Read the release notes before you upgrade.
- Major versions change the API, the self-hosted architecture, or default behavior. Read the upgrade notes.
image.tag to a specific version so deployments are repeatable.
When to upgrade
Upgrade at least monthly. The further behind you fall, the bigger each upgrade and each rollback gets. Upgrade UAT first, check SSO, warehouse connections, dbt refreshes, scheduled deliveries, embeds and critical dashboards, then upgrade production. UAT needs the same configuration and environment variables as production, and a recent copy of the production Lightdash database. When a newer version is out, the page footer shows New version available!. Click it to see what changed since your version. SetLIGHTDASH_DISABLE_UPDATE_CHECK=true to turn this off.
Security fixes are published as GitHub Security Advisories. Watch them and deploy the fixed version they name. The security policy shows how to poll them automatically.
Check the upgrade
The check tells you whether the new version can replace the old one with a rolling update, or whether you have to stop the old version first (Recreate).
Each release publishes a release-safety.json file, on its GitHub release and in its Docker image. It records whether the release can run alongside the version before it, the migrations it runs, and any version you must upgrade through first. The CLI reads a public index of these files, so the check needs no Lightdash login or access to your instance.
- Install or update the Lightdash CLI to version
1.126.0or later. - Run
lightdash upgrade-checkwith the version you run now and the version you want:
0 only when the verdict is SAFE. Add --json for automation.
Read the result
The check covers every release after--from up to and including --to. One release that isn’t proven safe makes the whole upgrade UNSAFE.
Check for table locks and long migrations
To size a maintenance window, openrelease-safety.json from each GitHub release in your span. Each entry under migrations.files lists the tables it touches and whether it locksTable, rewritesTable or scansTable. A flag that is true or unknown means the migration may take a long time or block writes on a large table, so allow a longer window.
Pause anything that writes to those tables until the migration finishes. For example, a migration on saved_queries_versions competes for locks with every lightdash upload, because each upload writes new chart versions, so stop CI jobs that run uploads during the window.
config.changes in the same file lists environment variables the release removed, renamed, or gave a new default. Check it for any variable you set. The full format is in the release-safety schema.
Upgrade with Kubernetes and Helm
1
Take a database backup
Lightdash doesn’t run down-migrations in production, so a backup is the only way to undo a schema change. Take a fresh backup and confirm it restores.
2
Set the upgrade mode
Set With chart
upgrade.mode from the check: RollingUpdate for SAFE, Recreate for UNSAFE. Run migrations in a Job, which is recommended for any deployment with more than one replica:2.16.284 or later, this combination makes the chart remove the backend HorizontalPodAutoscaler (HPA), scale the backend and worker Deployments to zero, and wait for their pods to stop before running migrations. The chart stops the upgrade if shutdown or migration fails.3
Optional: scale workloads down by hand
Only for chart Helm restores the replicas and the backend HPA after a successful upgrade if autoscaling is enabled.
2.16.283 and earlier, or a custom deployment, with an UNSAFE verdict and the migration Job enabled. Old pods must not run against the new schema, so remove the backend HPA, scale to zero and wait until no Lightdash pods remain:4
Upgrade
Set the new The migration Job runs as a pre-install and pre-upgrade hook, and the backend starts without migrating. If you override
image.tag in your values file, then run:image.command, your command must also skip startup migrations. Without the Job, the first pod to start migrates and the others wait.5
Confirm the instance is ready
/api/v1/readyz returns 503 with reason: schema_pending while the running code needs migrations, or reason: db_unavailable when the database check fails. Once the schema is ready, it returns 200; a parked migration run or an uninitialized migration ledger appears in warnings without failing readiness. See health probes for which endpoint to use for which probe.These examples assume a release named lightdash. Find yours with kubectl get deploy,job -l app.kubernetes.io/instance=<release>.Upgrade with Docker Compose
Compose stops the old container before starting the new one, whatever the verdict. Plan for a few minutes of downtime, longer if the release has heavy migrations.1
Take a database backup
If Postgres runs in the Compose stack, back up its volume as well.
2
Check the upgrade
Run the check. If it reports required stops, upgrade to each one in turn.
3
Upgrade
Set the new image tag, then pull and recreate the container:The new container runs migrations before it accepts traffic.
4
Confirm the instance is ready
idle and 200.Automate upgrades
examples/upgrade-automation in the Lightdash repository is a reference GitHub Actions workflow. It runs the check, steps through required stops, and opens a pull request that bumps your pinned tag. Set auto_merge: 'true' to enable auto-merge for safe upgrades. Unsafe or unknown upgrades open as HOLD: pull requests for a person to review.
After deploying, the workflow requires three consecutive ready checks with the expected running version. A parked migration fails verification even when /api/v1/readyz returns 200. On failure, it opens a freeze issue and pauses upgrades until the issue is closed. It never rolls back automatically.
To build your own, set the Helm mode from the check on every run:
--set-string overrides any upgrade.mode in your values file.
Troubleshoot an upgrade
The Lightdash image includesmigrate commands for inspecting and recovering migrations. Run them inside the deployment, for example with kubectl exec deploy/lightdash-backend -- or docker compose exec lightdash:
status reports one of four states:
idle: nothing is running.migrating: a migration is running. Large tables can take a long time, so leave it alone.stale: the migrating process stopped responding. Another process takes over after 75 seconds.parked: a migration failed three times and stopped. Fix the cause and deploy a fixed version, or unlock and retry.
The migration Job failed
Read the Job’s logs first:migrationJob.ttlSecondsAfterFinished if you need longer. status keeps the failure details either way. After you fix the cause, re-run helm upgrade.
A Job whose pod never starts, for example one stuck Pending, holds the upgrade open indefinitely, because backoffLimit only counts pods that start. To cap it, set migrationJob.activeDeadlineSeconds, sized to cover the scale-down wait (migrationJob.scaleDownWorkloads.timeoutSeconds, default 300), the image pull and your longest migration. If the deadline fires after the scale-down, the upgrade fails with every workload still at zero replicas. When you set a deadline, also raise migrationJob.ttlSecondsAfterFinished, so a Job stopped by the deadline keeps its logs long enough to read.
The cluster autoscaler can evict the migration pod while it drains a node, which stops the migration partway. To prevent this, annotate the pod:
Release a lock
unlock refuses while a live process holds the lease or a lock remains in knex_migrations_lock. Stop any process using those locks before you use --force. Afterwards, re-run helm upgrade if you use the migration Job, or docker compose restart lightdash with Docker Compose.
Preflight a new image
To find problems before a maintenance window, runpreflight on the new image without migrating. With Docker Compose:
MIGRATION_PREFLIGHT_DISK_HEADROOM_BYTES to the available bytes; PostgreSQL cannot report this value, so leaving it unset produces a warning. Preflight ends with proceed, proceed-with-warnings, abort or force-proceed. --strict treats warnings as blockers, and --force overrides an abort.
Roll back
Roll back by redeploying the previous image tag. This keeps the migrated schema; to undo schema changes, restore a backup and lose everything written since. Roll back promptly, because the new version may write data the old one can’t read.upgrade-check rejects rollback spans. An image from 1.259.1 or later can start against a database with newer migrations when every migration that image needs has already run. This does not guarantee that older application code can read data written by the newer release.
To rebuild an instance from scratch you need the Postgres backup, your LIGHTDASH_SECRET and your Helm values. Without LIGHTDASH_SECRET you can’t decrypt data stored in the database.
Update the Lightdash CLI
After an upgrade, everyone who uses the CLI should update it to match the instance. If you run Lightdash on your laptop with Docker, pull the latest image withdocker pull lightdash/lightdash and restart.