Skip to main content
🛠 This page is for engineering teams self-hosting their own Lightdash instance. If you’re on Lightdash Cloud, upgrades are handled for you automatically.

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.
Lightdash ships continuously and has no LTS tag. In production, pin 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. Set LIGHTDASH_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.
Ask your AI coding agent to do this for you with the upgrade-preflight agent skill, which runs lightdash upgrade-check and migrate preflight and walks you through the result.
  1. Install or update the Lightdash CLI to version 1.126.0 or later.
  2. Run lightdash upgrade-check with the version you run now and the version you want:
The command exits 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, open release-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 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:
With chart 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 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:
Helm restores the replicas and the backend HPA after a successful upgrade if autoscaling is enabled.
4

Upgrade

Set the new image.tag in your values file, then run:
The migration Job runs as a pre-install and pre-upgrade hook, and the backend starts without migrating. If you override 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

Expect 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 includes migrate 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.
Don’t edit the knex_migrations_lock table by hand. A live migration may own those locks. Use status to look and unlock to release.

The migration Job failed

Read the Job’s logs first:
Kubernetes deletes the Job, with its logs, about 100 seconds after it finishes. Raise 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, run preflight on the new image without migrating. With Docker Compose:
On Kubernetes, run the same command as a one-off Job on the new tag with your backend’s ConfigMap and Secret. Preflight checks the migration path, PostgreSQL version, privileges, and locks or long transactions on the affected tables. When a pending migration scans or rewrites a table, preflight also checks for at least 5 GiB of free disk. Set 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 with docker pull lightdash/lightdash and restart.