Spreading Updates
When a tag moves to a new version, every device tracking the tag installs the version on its next check. A spread releases the update to devices gradually instead, so that problems with a release surface while only a small share of the fleet has installed it. A spread can release devices automatically over a configured duration, up to a percentage that you raise manually, or both. The devices determine on their own whether they may update, so a spread needs no per-device rollout management.
Spreading is an optional feature of an integration. An integration that supports
it lists spread in the capabilities of its status. Other integrations ignore
the setting and install the target without waiting.
Device Positions
Each device derives a position between 0 and 1 from its device ID and the ID of the target version. A spread releases devices in the order of their positions: a device with position 0.12 may update once 12% of the fleet is released.
Positions are fixed. A device needs no stored state to know whether it may update, its eligibility does not depend on how often it checks, and Nexigon Hub can compute the schedule of every device. Because the position depends on the target version, different devices go first with each release. For a fixed group of devices that always update first, use a canary tag or a fleet operation instead.
Spreading over Time
A spread over time releases devices automatically over a duration:
{
"path": "acme/gateway-os/stable",
"spread": { "durationSecs": 604800 }
}The share of released devices grows quadratically with the elapsed time:
| Elapsed Time | Released Devices |
|---|---|
| 10% | 1% |
| 25% | 6% |
| 50% | 25% |
| 75% | 56% |
| 100% | 100% |
Few devices update early, while problems with a new release are most likely to surface, and the pace increases as the release proves itself. A device that is offline when it is released updates as soon as it reconnects.
By default, the spread starts when the tag in the configured path was assigned
to its current version. Nexigon Hub records this time for every tag. In the
example, moving stable to a new version starts a new seven-day spread, and
the configuration does not change between releases.
An explicit startAt overrides the tag’s assignment time:
{
"path": "acme/gateway-os/pkg_v_3sLgP9eKd7XwHn2QaRt5Zm",
"spread": { "startAt": "2026-10-19T06:00:00Z", "durationSecs": 259200 }
}Use an explicit start to spread an update to a version pinned by ID, or to begin a spread at a planned time, independent of when the version was tagged. Without an explicit start, updates to versions pinned by ID are not spread over time. The explicit start also applies to later targets. If the configured tag moves after the start, devices released at that point install the new version right away.
Releasing a Percentage
A percentage releases the update to a share of devices right away. Raise it step by step to release a version manually:
{
"path": "acme/gateway-os/pkg_v_3sLgP9eKd7XwHn2QaRt5Zm",
"spread": { "percentage": 5 }
}Raising the percentage only adds devices. The devices released at 5% remain
released at 20%, so you can go from 5% to 20% to 100% while observing the
fleet. Fractions such as 0.5 release a share smaller than one percent.
The percentage applies to whichever version is the target. If the configured tag moves, the new version is released to the same percentage right away. Pin the version by ID for manual releases, or lower the percentage before moving the tag.
Combining Both
With both a duration and a percentage, the percentage caps the spread over time. For example, the following spread releases devices over a week, but never more than 20% until you raise the percentage:
{
"path": "acme/gateway-os/stable",
"spread": { "durationSecs": 604800, "percentage": 20 }
}When you raise the cap, devices whose turn in the spread over time has already passed update right away.
Waiting for a Turn
While a device is not released, it reports the state blocked with the code
spread. If the device knows when it will be released, nextAttemptAt holds
that time:
{
"currentVersion": "2.1",
"state": "blocked",
"blocked": { "code": "spread" },
"targetVersionId": "pkg_v_3sLgP9eKd7XwHn2QaRt5Zm",
"nextAttemptAt": "2026-10-18T21:33:52Z"
}nextAttemptAt is absent for a device outside the released percentage, as its
release depends on the next change to the percentage.
Once released, the device proceeds as usual. It waits for its maintenance window, installs any checkpoints the target requires, and retries failed attempts according to its retry policy. The spread applies to the target, so the steps through checkpoints do not wait for further releases.
Halting a Spread
To halt a spread, hold the devices.
Devices that have not updated yet stay where they are, devices that have
already updated keep the new version, and all of them report the code hold.
A hold does not stop the clock of a spread over time. Removing the hold releases every device whose turn passed in the meantime at once. To resume gradually instead, set a percentage below the share already released, then remove the hold and raise the percentage step by step.
To revert the release, move the tag back to the previous version and remove any hold. Devices that have already updated then install the previous version again, unless going back crosses a checkpoint. Without an explicit start, they do so over a new spread that starts with the reassignment.
Computing Eligibility
Integrations must determine whether a device is released exactly as follows, so that Nexigon Hub predicts the same schedule as the devices:
- Compute the SHA-256 digest of the UTF-8 string
<device-id>/<target-version-id>. - Read the first 8 bytes of the digest as a big-endian unsigned integer
n. The position isu = floor(n / 2¹¹) / 2⁵³. It uses the top 53 bits ofn, so that a double-precision number representsuexactly and0 ≤ u < 1. - With
percentage, the device is released only ifu < percentage / 100. - With
durationSecs, determine the start of the spread:startAtif set, otherwise the time at which the tag in the configured path was assigned to its current version. The tag’s assignment time is theassignedAtfield of the tag in the version details. If neither exists, skip this step. Otherwise, the device is released only from the start plusfloor(durationSecs × √u)seconds, computed with IEEE 754 double-precision arithmetic.
A device is released when all applicable conditions hold. For example, with a seven-day spread starting on 2026-10-12 at 08
UTC:| Step | Value |
|---|---|
| Input string | d_5mKpR3vXq8TzLw2NhYc7Bf/pkg_v_3sLgP9eKd7XwHn2QaRt5Zm |
| First bytes | e1 2f 3c 23 99 59 8d 1c |
n | 16226254106033491228 |
u | 0.8796269976531673 |
| Delay | 567232 seconds |
| Released | From 2026-10-18T21:33:52Z |
With an additional percentage, the device is released only once the percentage exceeds 87.96.