Files
zitadel/apps/docs/content/self-hosting/manage/updating_scaling.mdx
T
8395d4326e docs: add v3 to v4 upgrade and Login V2 adoption guides (#12443)
<!--
Please inform yourself about the contribution guidelines on submitting a
PR here:
https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#submit-a-pull-request-pr.
Take note of how PR/commit titles should be written and replace the
template texts in the sections below. Don't remove any of the sections.
It is important that the commit history clearly shows what is changed
and why.
Important: By submitting a contribution you agree to the terms from our
Licensing Policy as described here:
https://github.com/zitadel/zitadel/blob/main/LICENSING.md#community-contributions.
-->

# Which Problems Are Solved

- Operators upgrading from ZITADEL v3 to v4 lacked a clear, docs-backed
upgrade path covering web keys (A-10017), Login V1 vs Login V2
expectations, and post-upgrade options.
- There was no standalone guide for adopting Login V2 after already
running on v4.
- Related ops/docs pages did not consistently point readers to the
upgrade and Login V2 adoption material.
- Kubernetes/Helm operators upgrading to a chart that ships ZITADEL v4
had no ops-page section linking the advisory, upgrade guide, optional
Login V2 deferral (`login.enabled: false`), and chart README upgrade
notes.

# How the Problems Are Solved

- Adds technical advisory **A-10017** documenting OIDC web key staging
requirements before upgrading to v4.
- Adds an **upgrade-v3-to-v4** guide with the recommended upgrade path
(Login V1 remains supported; Login V2 is optional at upgrade time).
- Adds a **v4-only adopt-login-v2** guide for teams adopting Login V2
later, with steps and caveats separate from the version upgrade.
- Adds an **Upgrading to ZITADEL v4** subsection under
`self-hosting/deploy/kubernetes/operations.mdx` that links to A-10017,
the upgrade guide, Adopt Login V2, notes `login.enabled: false` when not
adopting Login V2 yet, and points to the [Helm chart
README](https://github.com/zitadel/zitadel-charts/blob/main/charts/zitadel/README.md)
for chart-specific breaking changes.

# Additional Changes

- Registers new docs in the sidebar and wires Related / cross-links from
upgrade and ops pages so the advisory and guides are discoverable
together.
- Aligns language so upgrade vs. Login V2 adoption are clearly separated
concerns.
- Light cross-link updates on troubleshooting / updating-scaling /
login-client pages where related.

# Additional Context

- Related: A-10017 (web keys advisory)
- Docs paths introduced/updated:
  - `apps/docs/content/support/advisory/a10017.mdx`
  - `apps/docs/content/self-hosting/manage/upgrade-v3-to-v4.mdx`
  - `apps/docs/content/self-hosting/manage/adopt-login-v2.mdx`
- `apps/docs/content/self-hosting/deploy/kubernetes/operations.mdx` (new
"Upgrading to ZITADEL v4" section)
  - Sidebar and Related / cross-links
- Companion Helm chart README PR:
https://github.com/zitadel/zitadel-charts/pull/608

---------

Co-authored-by: Cursor <[email protected]>
2026-07-15 15:14:18 +00:00

108 lines
5.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Update and Scale ZITADEL
description: "Guidelines for updating and scaling ZITADEL instances, utilizing separate initialization and runtime phases for high availability."
sidebar_label: Update and Scale
---
## TL;DR
For getting started easily, you can just combine the init, setup and runtime phases
by executing the `zitadel` binary with the argument `start-from-init`.
However, to improve day-two-operations,
we recommend you run the init phase and the setup phase
separately using `zitadel init` and `zitadel setup` respectively.
Both the init and the setup phases are idempotent,
meaning you can run them as many times as you want without unexpectedly changing any state.
Nevertheless, they just __need__ to be run at certain points in time, whereas further runs are obsolete.
The init phase has to run once over the full ZITADEL lifecycle, before the setup and runtime phases run first.
The setup phase has to run each time a new ZITADEL version is deployed.
After init and setup is done, you can start the runtime phase, that immediately accepts traffic, using `zitadel start`.
## Scaling ZITADEL
For production setups, we recommend that you [run ZITADEL in a highly available mode](/self-hosting/manage/production).
As all shared state is managed in the database,
the ZITADEL binary itself is stateless.
You can easily run as many ZITADEL binaries in parallel as you want.
If you use [Knative](https://knative.dev/docs/)
or [Google Cloud Run](https://cloud.google.com/run) (which uses Knative, too),
you can even scale to zero.
Especially if you use an autoscaler that scales to zero,
it is crucial that you minimize startup times.
## Updating ZITADEL
When want to deploy a new ZITADEL version,
the new versions setup phase takes care of database migrations.
You generally want to run the job in a controlled manner,
so multiple executions don’t interfere with each other.
Also, after the setup is done,
rolling out a new ZITADEL version is much faster
when the runtime processes are just executed with `zitadel start`.
If you are upgrading from **v3 to v4**, see [Upgrade from ZITADEL v3 to v4](/self-hosting/manage/upgrade-v3-to-v4) and technical advisory [A-10017](/support/advisory/a10017) for the recommended staging path around OIDC web keys.
## Separating Init and Setup from the Runtime
If you use the [official ZITADEL Helm chart](/self-hosting/deploy/kubernetes),
then you can stop reading now.
The init and setup phases are already separated and executed in dedicated Kubernetes Jobs.
If you use another orchestrator and want to separate the phases yourself,
you should know what happens during these phases.
### The Init Phase
The command `zitadel init` ensures the database connection is ready to use for the subsequent phases.
It just needs to be executed once over ZITADELs full life cycle,
when you install ZITADEL from scratch.
`zitadel init` performs two steps that require different privileges:
**Provisioning step** (requires a PostgreSQL superuser):
- If it doesn’t exist already, it creates the unprivileged database user.
Subsequent phases connect to the database with this user’s credentials only.
- If it doesn’t exist already, it creates a database with the configured database name.
- If not already done, it grants the necessary permissions to the unprivileged user.
**Schema bootstrapping step** (requires database owner privileges, uses the service user):
- If they don’t exist already, it creates all schemas (`eventstore`, `projections`, `system`) and base tables.
<Callout type="info">
**Manual provisioning:** If you handle the provisioning step yourself (e.g. on a managed PostgreSQL service where you don’t have superuser access),
you can skip it entirely by running only the schema bootstrapping step:
```bash
zitadel init schema
```
This sub-command connects using the service user credentials and only performs schema bootstrapping.
No `Admin.*` credentials are required.
See the [database documentation](/self-hosting/manage/database) for full details.
</Callout>
The init phase is idempotent if executed with the same binary version.
### The Setup Phase
During `zitadel setup`, ZITADEL creates projection tables and migrates existing data, if `--init-projections=true` is set.
Depending on the ZITADEL version and the runtime resources,
this step can take several minutes.
When deploying a new ZITADEL version,
make sure the setup phase runs before you roll out the new `zitadel start` processes.
The setup phase is executed in subsequent steps
whereas a new version's execution takes over where the last execution stopped.
Some configuration changes are only applied during the setup phase, like ExternalDomain, ExternalPort and ExternalSecure.
The setup phase is idempotent if executed with the same binary version.
### The Runtime Phase
The `zitadel start` command assumes the database is already initialized and set up.
It starts serving requests within fractions of a second.
Beware, in the background, out-of-date projections
[recompute their state by replaying all missed events](/concepts/eventstore/implementation#projections).
If a new ZITADEL version is deployed, this can take quite a long time,
depending on the amount of events to catch up.
You probably should consider providing `--init-projections=true`-flag to the [Setup Phase](#the-setup-phase) to shift the synchronization time to previous steps and delay the startup phase until events are caught up.