This document describes how to upgrade a Spanner Omni deployment from an earlier version to a later version.
Spanner Omni uses an asynchronous, phased rollout state machine to help ensure safe upgrades without service disruption. Upgrading in phases lets you do the following:
- Apply database schema updates.
- Verify binary compatibility during a rolling restart.
- Roll back to the earlier version if you detect errors before finalization.
Upgrade workflow
The Spanner Omni upgrade process consists of multiple sequential phases:
- Schema phase: Prepares the deployment by running internal database schema migrations using the target binary version. Schema migrations can't be rolled back, but they are backward-compatible with the earlier binary version.
- Binary phase: Updates the server binary or container image across all servers in the deployment using a rolling restart. If you detect errors, you can roll back the binary or container image to the earlier version at any point before finalization begins.
- Enable features phase: Enables version-compatible features and starts after you upgrade the binary on all servers. This phase might not apply if the upgrade doesn't include version-compatible features, and it can require multiple rounds if features are interdependent. For optional phases that support rollback, you can initiate a rollback using the Spanner Omni CLI.
- Finalize phase: Finalizes the rollout, sealing the target version. After the finalize phase begins, rollbacks aren't possible.
Before you begin
Before you upgrade your Spanner Omni deployment, ensure you meet the following prerequisites:
- You have a running Spanner Omni deployment. For more information, see Create a deployment on Kubernetes or Create a deployment on VMs.
- You downloaded and installed the Spanner Omni CLI.
- You have network access to all Spanner Omni internal ports (TCP 15000 to 15027) from the machine where you run the CLI commands, or network access to your deployment endpoint.
- If your deployment uses Transport Layer Security (TLS) or mutual TLS (mTLS)
encryption, ensure valid certificates are available in your base directory
under
BASE_DIR/tlsor mounted in your cluster. - You identified your target release:
- For VM deployments: download the target release package
spanner-omni-server-TARGET_VERSION.tar.gz. - For Helm and Kubernetes deployments: identify the target container
image in Artifact Registry, such as
us-docker.pkg.dev/spanner-omni/images/spanner-omni:TARGET_VERSION.
- For VM deployments: download the target release package
Step 1: Prepare the schema upgrade
To initiate the upgrade, prepare the rollout for the target version. In this phase, Spanner Omni runs internal database schema migrations while existing servers continue serving traffic.
Select the tab for your deployment environment:
VM
In VM deployments, download and extract the target release package, and then use the extracted Spanner Omni CLI to initiate rollout preparation.
Sign in to a server in your deployment that has network access to all Spanner Omni internal ports (TCP 15000 to 15027).
Download and extract the target release package:
tar -xzf spanner-omni-server-TARGET_VERSION.tar.gz -C EXTRACT_DIRReplace the following:
TARGET_VERSION: The target version to upgrade to, for example,2026.r4-lts.EXTRACT_DIR: The directory where you extract the release package, for example,/tmp/target_spanner/.
Initiate rollout preparation by running the
rollouts preparecommand from the extracted CLI:EXTRACT_DIR/bin/spanner deployment rollouts prepare \ --target-server-binary=EXTRACT_DIR/bin/spanner_server \ --root-server=ROOT_SERVERS \ --base-dir=BASE_DIRReplace the following:
EXTRACT_DIR: The extraction directory containing the targetbin/spannerCLI andbin/spanner_serverbinary.ROOT_SERVERS: One root server endpoint or a comma-separated list of multiple root servers, for example,localhost:15000orserver1:15000,server2:15000,server3:15000.BASE_DIR: The base directory for Spanner Omni, for example,/spanner.- If your deployment uses TLS or mTLS encryption, append
--ca-certificate-file=CA_CERT_FILEand--client-certificate-directory=CERT_DIRpointing to valid certificates.
Helm
In Helm deployments, schema preparation depends on whether you run a multi-server or single-server deployment:
Multi-server deployments (High availability / Production): Helm automatically handles schema preparation. When you run
helm upgradein Step 3: Update the binary or container image, the Helm chart triggers thespanner-prepare-for-upgradepre-upgrade hook job to run schema migrations before updating any StatefulSets. Proceed directly to Step 2: Verify the active rollout state.Single-server deployments (
deployment.singleServer=true): Because single-server mode binds internal services strictly to the loopback interface (127.0.0.1), network jobs can't reach them. Run the schema migration locally inside the running pod using an ephemeral debug container with the target container image:kubectl debug pod/POD_NAME -n NAMESPACE \ --image=us-docker.pkg.dev/spanner-omni/images/spanner-omni:TARGET_VERSION \ --container=upgrade-prepare -i \ -- /google/spanner/bin/spanner_server prepare_for_upgrade --root_server=127.0.0.1Replace the following:
POD_NAME: The name of the server pod, for example,spanner-a-0.NAMESPACE: The Kubernetes namespace of the deployment, for example,spanner-ns.TARGET_VERSION: The target version to upgrade to, for example,2026.r4-lts.
Standalone Kubernetes
If you deploy Spanner Omni on Kubernetes without Helm, run a standalone Kubernetes batch job to execute schema migrations against the active root server using the target image.
Create a file named
spanner-prepare-upgrade.yamlwith the following job manifest:apiVersion: batch/v1 kind: Job metadata: namespace: NAMESPACE name: spanner-prepare-for-upgrade spec: # Fail fast on the first error to stop the rollout immediately. backoffLimit: 0 template: metadata: namespace: NAMESPACE spec: restartPolicy: Never containers: - name: spanner-upgrade image: us-docker.pkg.dev/spanner-omni/images/spanner-omni:TARGET_VERSION command: ["/google/spanner/bin/spanner_server"] args: - "prepare_for_upgrade" - "--root_server=ROOT_SERVER_ENDPOINT" volumeMounts: - name: tls-certs mountPath: "/spanner/tls" readOnly: true - name: spanner-data mountPath: /spanner volumes: - name: tls-certs secret: secretName: tls-certs optional: true defaultMode: 256 - name: spanner-data emptyDir: {}Replace the following:
NAMESPACE: The Kubernetes namespace of the deployment, for example,spanner-ns.TARGET_VERSION: The target version to upgrade to, for example,2026.r4-lts.ROOT_SERVER_ENDPOINT: The endpoint of an active root server pod, for example,spanner-a-0.pod.spanner-ns.
Apply the manifest to run the preparation job:
kubectl apply -f spanner-prepare-upgrade.yaml
Step 2: Verify the active rollout state
After the preparation step completes, verify that the rollout was created and inspect its phase status.
List the active rollouts to retrieve the rollout ID:
spanner deployment rollouts list \ --deployment-endpoint=DEPLOYMENT_ENDPOINTReplace
DEPLOYMENT_ENDPOINTwith the endpoint of a server in your deployment, for example,localhost:15000orspanner-a-0.pod.spanner-ns:15000.The output is similar to the following:
NAME STATE TARGET_VERSION START_TIME END_TIME rollouts/1788942172101727 IN_PROGRESS 2026.r3-beta 2026-09-09T08:22:52.101727Z -Inspect the detailed rollout phase status:
spanner deployment rollouts describe ROLLOUT_ID \ --deployment-endpoint=DEPLOYMENT_ENDPOINTReplace the following:
ROLLOUT_ID: The numeric rollout ID, for example,1788942172101727.DEPLOYMENT_ENDPOINT: The endpoint of a server in your deployment.
The output is similar to the following:
name: rollouts/1788942172101727 phases: - name: rollouts/1788942172101727/phases/schema startTime: "2026-09-09T08:22:52.101727Z" state: SUCCEEDED - name: rollouts/1788942172101727/phases/binary startTime: "2026-09-09T08:23:29.585375Z" state: IN_PROGRESS - name: rollouts/1788942172101727/phases/finalize state: PENDING sourceVersion: 2026.r2-beta.3 startTime: "2026-09-09T08:22:52.101727Z" state: IN_PROGRESS targetVersion: 2026.r3-betaVerify the following phase statuses before proceeding:
schema: ShowsSUCCEEDED, indicating that internal database schema migrations completed.binary: ShowsIN_PROGRESS, indicating that the rollout engine is ready for binary updates.finalize: ShowsPENDING, awaiting completion of the binary phase.
Step 3: Update the binary or container image
After the schema phase succeeds, update the running server binary or container image across all nodes in the deployment to the target version.
Select the tab for your deployment environment:
VM
In VM deployments, update the spanner_server binary across all VMs using
a rolling restart:
- Update one failure domain or zone at a time: In multi-zone deployments, update servers in one zone and verify stability before updating the next zone. This ensures that the Paxos consensus group retains quorum.
- Restart progressively: Restart no more than 5% of servers simultaneously to maintain continuous query availability.
- Verify server health: Ensure that all restarted servers are healthy and have rejoined the cluster before updating the next failure domain.
Helm
In Helm deployments, run helm upgrade while preserving your existing
configuration values by passing --reuse-values or providing a values file:
Multi-server deployments (Production / HA):
helm upgrade spanner-omni oci://us-docker.pkg.dev/spanner-omni/charts/spanner-omni \ --version CHART_VERSION \ -n NAMESPACE \ --reuse-values \ --set image.tag=TARGET_VERSION \ --timeout 30mHelm automatically executes Phase 1 using the pre-upgrade hook, and then initiates a sequential, zone-by-zone rolling update of the StatefulSets (
rollout.staggered: true).Single-server deployments (
deployment.singleServer=true):Explicitly pass
--set skipPrepareUpgrade=trueso Helm skips the pre-upgrade hook job, because you already completed Phase 1 locally:helm upgrade spanner-omni oci://us-docker.pkg.dev/spanner-omni/charts/spanner-omni \ --version CHART_VERSION \ -n NAMESPACE \ --reuse-values \ --set skipPrepareUpgrade=true \ --set image.tag=TARGET_VERSION \ --timeout 30m
Replace the following:
CHART_VERSION: The target Helm chart version, for example,1.0.NAMESPACE: The Kubernetes namespace of the deployment, for example,spanner-ns.TARGET_VERSION: The target container image tag, for example,2026.r4-lts.
Standalone Kubernetes
In custom Kubernetes deployments without Helm, update the container image
in your StatefulSet or Deployment specifications to
TARGET_VERSION.
Perform a rolling update across failure domains, updating one zone at a time and restarting no more than 5% of pods simultaneously to preserve quorum.
Step 4: Verify binary phase progression
After you update all servers or pods to the target version, verify that the binary phase completes successfully.
Check the rollout phase status:
spanner deployment rollouts describe ROLLOUT_ID \
--deployment-endpoint=DEPLOYMENT_ENDPOINT
Replace the following:
ROLLOUT_ID: The numeric rollout ID, for example,1788942172101727.DEPLOYMENT_ENDPOINT: The endpoint of a server in your deployment.
The output is similar to the following:
name: rollouts/1788942172101727
phases:
- name: rollouts/1788942172101727/phases/schema
startTime: "2026-09-09T08:22:52.101727Z"
state: SUCCEEDED
- name: rollouts/1788942172101727/phases/binary
startTime: "2026-09-09T08:23:29.585375Z"
state: SUCCEEDED
- name: rollouts/1788942172101727/phases/finalize
state: PENDING
sourceVersion: 2026.r2-beta.3
startTime: "2026-09-09T08:22:52.101727Z"
state: IN_PROGRESS
targetVersion: 2026.r3-beta
Confirm that the binary phase status changes to SUCCEEDED. The overall
rollout state remains IN_PROGRESS until all remaining phases complete. After
phases/binary transitions to SUCCEEDED, the deployment is ready to proceed
to the remaining phases.
Step 5: Schedule and execute remaining phases
When the binary phase succeeds and you verify that your deployment is stable,
schedule the remaining phases for the rollout up to the finalize phase.
The finalize phase (the last phase of a rollout) seals the new version across
the deployment. You can run this command from any machine that has network
access to the Spanner Omni service by specifying
--deployment-endpoint.
For each remaining phase in the PENDING state (such as enable_features if
present, followed by finalize), complete the following steps:
Schedule the phase:
spanner deployment rollouts phases schedule PHASE_NAME \ --rollout=ROLLOUT_ID \ --deployment-endpoint=DEPLOYMENT_ENDPOINTReplace the following:
PHASE_NAME: The name of the phase to schedule, for example,finalizeorenable_features.ROLLOUT_ID: The numeric rollout ID, for example,1788942172101727.DEPLOYMENT_ENDPOINT: The endpoint of a server in your deployment.
The output indicates that the scheduled phase is
IN_PROGRESS:name: rollouts/1788942172101727 phases: - name: rollouts/1788942172101727/phases/schema startTime: "2026-09-09T08:22:52.101727Z" state: SUCCEEDED - name: rollouts/1788942172101727/phases/binary startTime: "2026-09-09T08:23:29.585375Z" state: SUCCEEDED - name: rollouts/1788942172101727/phases/finalize state: IN_PROGRESS sourceVersion: 2026.r2-beta.3 startTime: "2026-09-09T08:22:52.101727Z" state: IN_PROGRESS targetVersion: 2026.r3-betaWait for the phase to succeed, and verify its status:
spanner deployment rollouts describe ROLLOUT_ID \ --deployment-endpoint=DEPLOYMENT_ENDPOINTRepeat these steps for each remaining phase until all phases up to and including
finalizeare complete.After the final phase (
finalize) completes, all phases and the overall rollout state transition toSUCCEEDED:endTime: "2026-09-09T08:45:43.949702Z" name: rollouts/1788942172101727 phases: - name: rollouts/1788942172101727/phases/schema startTime: "2026-09-09T08:22:52.101727Z" state: SUCCEEDED - name: rollouts/1788942172101727/phases/binary startTime: "2026-09-09T08:23:29.585375Z" state: SUCCEEDED - name: rollouts/1788942172101727/phases/finalize startTime: "2026-09-09T08:45:43.898111Z" state: SUCCEEDED sourceVersion: 2026.r2-beta.3 startTime: "2026-09-09T08:22:52.101727Z" state: SUCCEEDED targetVersion: 2026.r3-betaConfirm the completed status in the rollouts list:
spanner deployment rollouts list \ --deployment-endpoint=DEPLOYMENT_ENDPOINTThe output confirms that the rollout is complete:
NAME STATE TARGET_VERSION START_TIME END_TIME rollouts/1788942172101727 SUCCEEDED 2026.r3-beta 2026-09-09T08:22:52.101727Z 2026-09-09T08:45:43.949702Z
Roll back an upgrade
If you encounter issues during an upgrade, whether you can roll back the upgrade depends on its current rollout phase:
- Schema phase: can't be rolled back. Internal database schema migrations applied during preparation are forward-only and can't be reverted. However, schema migrations are backward-compatible with the source version, allowing earlier server binaries to continue operating normally.
- Binary phase: can be rolled back to the earlier version at any point before finalization begins. For more information, see Roll back the binary or container image.
- Optional rollout phases: for optional phases that support automated rollback (such as feature enablement), initiate the rollback using the Spanner Omni CLI.
- Finalize phase: can't be rolled back. After finalization begins, the target version is permanently sealed across the deployment and rollbacks aren't possible.
Roll back the binary or container image
To roll back the binary phase before finalization begins, perform a rolling restart across all servers or pods to restore the earlier (source) version.
VM
In VM deployments, roll back the spanner_server binary across all VMs:
- Deploy the earlier
spanner_serverbinary version to your hosts. - Restart servers progressively across failure domains, updating one zone at a time and restarting no more than 5% of servers simultaneously to preserve Paxos quorum.
- Verify that all restarted servers are healthy and have rejoined the cluster before proceeding to the next failure domain.
Helm
In Helm deployments, update the container image tag back to the earlier version:
helm upgrade spanner-omni oci://us-docker.pkg.dev/spanner-omni/charts/spanner-omni \
--version CHART_VERSION \
-n NAMESPACE \
--reuse-values \
--set image.tag=SOURCE_VERSION \
--timeout 30m
Replace the following:
CHART_VERSION: The Helm chart version, for example,1.0.NAMESPACE: The Kubernetes namespace of the deployment, for example,spanner-ns.SOURCE_VERSION: The earlier container image tag to revert to, for example,2026.r2-beta.3.
Standalone Kubernetes
In custom Kubernetes deployments without Helm, update the container image
in your StatefulSet or Deployment specifications back to
SOURCE_VERSION.
Perform a rolling update across failure domains, updating one zone at a time and restarting no more than 5% of pods simultaneously to preserve quorum.
Roll back optional rollout phases
For optional rollout phases that support rollback (such as feature enablement
phases), initiate the rollback by running the rollouts rollback command:
spanner deployment rollouts rollback ROLLOUT_ID \
--deployment-endpoint=DEPLOYMENT_ENDPOINT
Replace the following:
ROLLOUT_ID: The numeric rollout ID.DEPLOYMENT_ENDPOINT: The endpoint of a server in your deployment.
What's next
- Learn how to Maintain a deployment.
- Learn how to Scale a Kubernetes deployment or Scale a VM deployment.
- Learn about Monitoring overview.