Skip to main content

Rollouts

A rollout is the gradual release of a new version to a percentage of your users. Instead of pushing a bundle to 100% of devices at once, you release to 5%, then 25%, then 50%, then everyone — pausing at each step to verify the new release is healthy.

Swiftpatch treats rollouts as a first-class primitive. Every release has a rollout percent; devices are deterministically bucketed so the same device stays in the same bucket across releases.

Setting the rollout percent

From the CLI:

# Deploy to 5% of users
swiftpatch deploy -p ios --hermes --rollout 5

# Update an existing release's rollout percent
swiftpatch releases rollout r_abc123 --percent 25

From the dashboard, drag the rollout slider per release.

Deterministic bucketing

Each device lands in a deterministic bucket [0, 100) based on a hash of deviceId + deploymentKey. If the release's rollout is N%, devices with bucket < N receive the release.

Properties of this bucketing:

  • Stable across releases. A device in bucket 7 is in bucket 7 forever. Moving from 5% → 10% adds new devices; it doesn't shuffle existing ones.
  • Independent per deployment key. A device in bucket 7 on production may be in bucket 43 on beta.
  • No cohort memory. The bucket is computed client-side, so there's no server lookup.

Result: if you roll out to 5% and see a spike in crashes, you've affected only the specific 5% of users in buckets 0–4 — the same 5% who saw the previous 5% rollout. If they're a good canary cohort, keep going. If you find yourself always hitting the same users, rotate deploymentKey suffixes or use cohorts (next section).

Cohorts

For targeted rollouts, cohorts let you scope a release to a subset of users beyond just percent:

swiftpatch deploy --cohort internal-testers --rollout 100
swiftpatch deploy --cohort us-west --rollout 50

A cohort is a label your app reports at check-time:

import { Swiftpatch } from '@swiftpatch/react-native';

// On app startup or after the user joins internal-testers
await Swiftpatch.setCohorts(['internal-testers', 'us-west']);

The check-for-update API filters by cohort membership. Users not in a given cohort never see releases targeted at it.

Auto-pause on crash rate

Each channel has an auto-pause-crash-rate policy. When the crash rate on a live release exceeds the threshold:

  1. Rollout auto-pauses at its current percent.
  2. Dashboard incident opens.
  3. Release owners receive email + Slack notifications.

Default threshold: 0.5% above baseline (the channel's baseline crash rate over the trailing 7 days).

Override per channel:

swiftpatch channels update production --auto-pause-crash-rate 0.3

Staged rollout recipe

The default production rollout cadence:

# Day 0, 09:00
swiftpatch deploy -p ios --hermes --rollout 1 --release-note "v1.2.3"

# Day 0, 12:00 — verify dashboard shows no elevated crash rate
swiftpatch releases rollout r_new --percent 5

# Day 0, 17:00
swiftpatch releases rollout r_new --percent 25

# Day 1, 09:00
swiftpatch releases rollout r_new --percent 50

# Day 1, 14:00 — full rollout
swiftpatch releases rollout r_new --percent 100

See Staged rollouts guide for CI automation that does this for you.

Paused releases

Create a release in a paused state:

swiftpatch deploy --paused

The release is uploaded but invisible to devices. Devices won't see it until you set a rollout percent. Useful for pre-loading a release on the server that you want to ship at a specific time.

Live rollout status

swiftpatch status r_abc123

Opens an SSE stream showing:

  • Current rollout percent.
  • Number of devices eligible.
  • Number downloaded.
  • Number applied.
  • Number of crashes attributed to this release.
  • Current release status (ACTIVE, PAUSED, ROLLED_BACK, COMPLETED).

Add --json for one compact JSON object per line (useful in CI logs).

Mandatory releases

A mandatory release bypasses the user's "Later" dismissal. Set via the -m / --mandatory flag:

swiftpatch deploy -p ios --hermes --mandatory

When a mandatory release is ready, the provider renders <UpdateBlocker /> — a full-screen modal with no dismiss action. Use mandatory for security-critical fixes only.

Next steps