Upgrade Command
The upgrade command upgrades Talos OS on each node to the desired version specified in the installer image.
Flags
All flags can also be set via environment variables using the TOPF_ prefix and uppercasing the flag name (e.g. --reboot-mode → TOPF_REBOOT_MODE).
| Flag | Default | Description |
|---|---|---|
--dry-run |
false |
Only show what upgrades would be performed without actually upgrading |
--max-parallel |
1 |
Number of worker nodes to upgrade concurrently, as an integer (e.g. 5) or a percentage of the total node count (e.g. 25%); control-plane nodes are always upgraded one at a time |
--reboot-mode |
default |
Reboot mode during upgrade: default uses kexec, powercycle does a full reboot |
--drain |
true |
Cordon and drain the Kubernetes node before rebooting, then uncordon after stabilization (modern flow only; ignored on legacy nodes, where Talos drains and uncordons server-side) |
--drain-timeout |
5m |
Maximum time to wait for pod evictions (and, with --delete-if-eviction-fails, deletions) to complete during drain (modern flow only) |
--stabilization-duration |
30s |
How long a node must stay ready after rebooting before it is considered stable |
--delete-if-eviction-fails |
false |
If graceful drain fails (e.g. a PodDisruptionBudget blocks eviction), retry by deleting pods directly (DELETE instead of EVICT, bypassing PDBs); reuses --drain-timeout for the delete fallback (modern flow only) |
--force |
false |
Skip etcd health checks; only applies to nodes running Talos < 1.13 (legacy MachineService.Upgrade RPC); has no effect on Talos >= 1.13, where the LifecycleService.Upgrade RPC validates etcd health server-side |
--allow-not-ready |
false |
Allow upgrading nodes that are not ready (have unmet conditions) |
--stage |
false |
Install upgrade artifacts without rebooting; the node is left running and can be labeled/annotated/tainted (see --stage-label/--stage-annotation/--stage-taint) so an external controller or human reboots it later |
--stage-label |
- | Kubernetes node label to apply after staging (key=value); can be repeated; requires --stage |
--stage-annotation |
- | Kubernetes node annotation to apply after staging (key=value); can be repeated; requires --stage |
--stage-taint |
- | Kubernetes node taint to apply after staging (key=value:Effect); can be repeated; requires --stage |
--nodes-filter |
- | Regex pattern to filter which nodes to operate on (global flag) |
Behavior
- Pre-flight checks: Ensures all nodes are reachable, in a processable stage (
runningorbooting; a node inmaintenanceneeds its config applied first — seetopf apply), and ready (readiness check skipped with--allow-not-ready) - Version comparison: Extracts schematic and version from the installer image and only upgrades nodes where either differs from the current state
- Per-node confirmation: Before each upgrade (unless
--confirm=false, see global flags) - API selection: Per node, if the running Talos version is >= 1.13.0, the modern flow (a) is used; otherwise the legacy flow (b) is used
Modern flow (Talos >= 1.13):
- Resolve the Kubernetes node name (if
--drainis enabled or for staged upgrades with--stage-labeland/or--stage-taintand/or--stage-annotation) - Pre-pull the installer image via
ImageService.Pull - Install the upgrade artifacts via
LifecycleService.Upgrade - If
--stageis set: apply labels/annotations/taints (if any) and stop here — the node is not rebooted - Cordon and drain the Kubernetes node if
--drainis enabled. If the drain fails (e.g. a pod cannot be evicted within--drain-timeout), the upgrade aborts unless--delete-if-eviction-failsis set: in that case, the drain retries with pod deletion (DELETE instead of EVICT, bypassing PodDisruptionBudgets, reusing--drain-timeout). If the forced drain also fails, the node is left cordoned with the new artifacts installed but not rebooted, and no further nodes are upgraded. In-flight upgrades on other nodes (when--max-parallel > 1) are allowed to complete, but no new ones are started. The node must be uncordoned and rebooted manually to recover. - Issue a
Rebootwith the selected reboot mode (default: kexec) - Wait
--stabilization-duration(default: 30 seconds) for the node to stabilize - Uncordon the Kubernetes node
Legacy flow (Talos < 1.13):
- Issue
MachineService.Upgrade, which installs the upgrade artifacts, cordons and drains the node, and reboots — all in a single server-side sequence.--drainand--drain-timeoutare ignored (Talos drains and uncordons the node itself);--forceskips etcd health checks.--stageis not supported on legacy nodes. - Wait
--stabilization-duration(default: 30 seconds) for the node to stabilize
Installer Image
Using talosVersion and schematicId (recommended)
To override the installer image for the entire cluster, set talosVersion and optionally schematicId in topf.yaml. Topf will automatically generate a cluster-level patch:
This generates factory.talos.dev/metal-installer/<schematicId>:v<talosVersion> as the base installer image. Since this patch is applied first, any subsequent installer image patch (shared or node-level) will override it. The factory and platform can be customized via factory and platform in topf.yaml (or per node).
Talos >= 1.14: the installer image is injected as an
UnattendedInstallConfigdocument (.machine.installis deprecated and mutually exclusive with it). For older nodes it is still injected asmachine.install.image. Override patches must use the matching form for the node's version.
Manual installer image patch
Alternatively, manage the installer image explicitly via a patch. The target image for each node comes from the installer image field in the assembled node configuration (i.e. the last patch takes precedence). For Talos >= 1.14 the patch looks like:
all/00-install.yaml:
apiVersion: v1alpha1
kind: UnattendedInstallConfig
installer:
image: factory.talos.dev/metal-installer/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba:v1.14.0
For Talos < 1.14, use the legacy form:
machine:
install:
image: factory.talos.dev/metal-installer/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba:v1.12.0
Per-node override
To upgrade a single node to a different version or schematic, add a node-specific patch that overrides the image. For Talos >= 1.14:
node/node1/installer.yaml:
apiVersion: v1alpha1
kind: UnattendedInstallConfig
installer:
image: factory.talos.dev/metal-installer/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba:v1.14.0
For Talos < 1.14, use the legacy machine.install.image form instead.
Because node-level patches are merged last (see Configuration Model), this override applies only to that host.
Example Usage
# Upgrade with confirmation (default)
topf upgrade
# Upgrade without confirmation
topf upgrade --confirm=false
# Preview what would be upgraded
topf upgrade --dry-run
# Upgrade without draining the Kubernetes node
topf upgrade --drain=false
# Upgrade up to 3 worker nodes concurrently
topf upgrade --max-parallel=3
# Upgrade with a custom drain timeout
topf upgrade --drain-timeout=10m
# Force upgrade on legacy (Talos < 1.13) nodes, skipping etcd health checks
topf upgrade --force
# Upgrade, falling back to pod deletion if graceful drain fails
topf upgrade --delete-if-eviction-fails
# Upgrade with a longer drain timeout (shared by graceful and fallback)
topf upgrade --delete-if-eviction-fails --drain-timeout=10m
# Upgrade a node that is not ready (e.g. stuck with unmet conditions)
topf upgrade --allow-not-ready --nodes-filter '^node1$'
# Stage an upgrade without rebooting (reboot manually later to complete it)
topf upgrade --stage
# Stage an upgrade and label the node so a controller can find it
topf upgrade --stage --stage-label topf.postfinance.ch/staged-upgrade=true
# Stage an upgrade and taint the node to discourage new pods from scheduling
topf upgrade --stage --stage-taint topf.postfinance.ch/staged-upgrade=true:PreferNoSchedule
# Stage an upgrade and annotate the node so a controller can find it
topf upgrade --stage --stage-annotation topf.postfinance.ch/staged-at=2026-08-07