Concepts
Apps, channels, releases, rollouts and devices: the Relayer data model.
App
One piece of software you ship. An app has a display name (rename any time) and an immutable 16-character ref used in every URL and API call - so renaming never breaks shipped devices.
Channel
A distribution track: stable and beta exist by default; add more
(internal, canary, …) freely. Devices ask for updates on exactly one
channel. Each channel can carry a policy: a minimum supported version
and an update mode - devices below the minimum receive updates flagged
required.
Release
An immutable version published to a channel: version string, markdown release notes, and a list of artifacts (platform, arch, URL, sha512, size, optional code-signing signature). Relayer never stores your binaries - artifact URLs point at your existing storage.
A release has a status:
published- servable.paused- temporarily not served; resume any time.rolled_back- permanently withdrawn (cannot be resumed; publish a new version instead). Devices already ON it are served the newest published release below it as a downgrade (allowDowngrade).deprecated- end of life. Not served, but reversible (it is a policy, not an incident). Devices still on it are never downgraded - instead, the next update they are offered arrives withupdateMode: required, the mirror of the rollback rule.
It can also carry targeting - rules restricting which devices are eligible - and a rollout percentage ramping how many of those devices are offered it. Targeting has two parts, ANDed together:
- matchLabels - exact-match label rules: AND across keys, any-of within a key's values.
- matchExpressions - decision-time predicates:
{ key, operator, values }with operatorsIn,NotIn,Exists,DoesNotExist, plus semver-awareVersionGte/VersionLton the reserved$versionkey. Keys resolve against device labels, or against the request itself via$version,$platformand$arch- so "serve only devices below 2.0 on macOS" needs zero client changes. Every operator exceptDoesNotExistfails closed when its key cannot be resolved.
After a release's first offer, labels may only broaden - and expressions are frozen entirely (change them by cutting a new release). Full semantics, operators and examples: Targeting.
How serving decides (the mental model)
Relayer never pushes bytes. A device (or an orchestrator acting for it)
asks "I am X, running Y - what should I do?", and ONE decision function
answers - the same function behind /u/, the push-mode batch endpoint,
the electron feed, and the dashboard's "Why this update?" preview. They
share code, so the preview cannot disagree with production.
The walk: take every release in the device's channel, newest first, and find the first one that passes all five checks:
- Newer than the device's current version (else: up to date, stop).
- Published - paused, deprecated and rolled-back releases are skipped.
- Targeting matches - the device must satisfy every label rule (any-of within a key) AND every match expression. Devices that cannot satisfy a rule fail closed and skip the release.
- In the rollout -
sha256(deviceId:releaseId) % 100 < rolloutPct. Deterministic, so cohorts are sticky between checks. - Artifact exists for the device's platform/arch.
The property that makes this safe: a skip is never a dead end. A device outside a 10% rollout or a canary target falls through to the newest release below that it IS eligible for - excluding a device from the new thing never breaks its update path.
One exception to rule 1: if the device's current version was rolled back, the walk continues below it and serves a downgrade - a pulled build should never silently keep its victims.
Two invariants keep the dashboard honest, and both engage at the same moment: the first real offer. Until a release has been offered, rollout percentage and targeting are just a plan - edit them freely. Once offered, the percentage only increases (buckets are sticky, so decreasing never un-serves anyone - pause to halt, roll back to pull) and targeting only broadens (broadening is itself permanent).
Rollout percentage
Every release has a rollout percentage (default 100). At 25%, only a
quarter of eligible devices are offered that version - and when the
release is targeted, the percentage applies within the targeted cohort.
"On this version" on the Releases tab counts what devices actually report
running; offers always lead installs.
Device
An installation of your app, identified by an anonymous UUID that your app
generates and stores locally, sent in the X-Relayer-Device header. No
accounts, no PII. Every update check records version, platform, arch and
timestamp - that's the fleet dataset behind the dashboard.
Devices don't have to check in themselves: an orchestrator can report
state and plan update waves on their behalf via the
push-mode fleet API, optionally attaching labels -
opaque key/values (customerRef, siteRef, …) that Relayer stores and
echoes but never interprets.
Organization
The workspace everything lives in: apps, keys, devices and the audit log are organization-scoped, and teammates hold roles (owner / admin / member) within it. See Organizations & roles.
Audit log
Append-only record of every mutation - publishes, rollout changes, key mints, webhook deliveries - with actor, IP and timestamp. Mutations that cannot be audited do not happen.