Protected Tracks
On Enterprise, you can control who puts a patch in front of production users, and when:
- A protected track takes no patch until an admin or owner approves it. See Protect a track.
- A deployment freeze window blocks production changes for a period you set, such as a holiday or a weekend. See Deployment freezes.
Shorebird’s servers enforce both, so they hold whether you ship from the console, the CLI, CI or a service account.
Protect a track
Section titled “Protect a track”In an organization that’s part of an enterprise, an admin or owner, or an app
collaborator with the Admin role, can protect a track so
that no patch reaches it without a second person’s approval. Open the app’s
Tracks tab in the
Shorebird console and turn on Protected next to the track, usually stable.
Turning protection off is always possible, including after an organization leaves its enterprise. Requests already pending stay pending when protection is turned off: approve, reject, or cancel each one. An organization that leaves keeps its protected tracks, and patches sent to them still need approval. The console shows the Approvals tab only while the organization’s plan is Enterprise. Without the tab, reach the approvals page from the Waiting for approval banner or the link the CLI prints.
A protected track can’t be deleted until its protection is turned off.
Send a patch to a protected track
Section titled “Send a patch to a protected track”Publishing to a protected track, promoting a patch to it, or rolling forward a patch on it doesn’t ship the patch. Shorebird files an approval request instead, and the CLI prints a link to the app’s approvals page and exits with an error, so a CI job stops there:
A rollforward prints Approval requested to roll forward patch 4 in its place.
shorebird patch still uploads the patch, and a promoted patch stays on its
current track until the request is approved. Each release has at most one
pending request per track: a newer request, such as a rerun of the CI job,
replaces the older one. Approval is only needed to put a patch on a protected
track: rolling back a patch, or moving it off the track, never needs it. A patch
waiting for approval, or already on a protected track, takes no new artifacts,
so adding a platform or retrying an upload to it fails with
patch_artifacts_create_patch_under_approval. Create a new patch instead.
In CI, the failed step’s error code is patch_approval_required
(error.api_code in --json output), which
tells a waiting patch apart from a failed one. Run CI with a
service account rather than a person’s API key: a
request sent with your own key is your own request, which another admin or owner
has to approve, unless you’re an owner and give a reason.
While requests are pending, the app’s pages in the console show a Waiting for approval banner, and the release page marks the waiting patch.
Approve a request
Section titled “Approve a request”When a request is filed, every admin and owner of the organization except whoever asked gets an email linking to it. The app’s Approvals tab lists pending requests with the patch, release, track, and who asked. Admins and owners can Approve or Reject each one, with an optional comment. Approving puts the patch on the track at once; as with any patch, devices get it if it’s the highest-numbered patch there that isn’t rolled back. Approving fails, and the request stays pending, if:
- the organization’s enterprise has since started requiring signed patches and the patch isn’t signed,
- a rollforward’s patch has since moved off the track, or
- a deployment freeze window is active. Approve the request once the window ends.
Reject or cancel a request that can’t be approved. Rejecting leaves the patch where it is. Whoever asked can Cancel request instead, which also leaves the patch where it is.
App collaborators with the Admin role can approve and reject requests and protect tracks too, but they aren’t emailed when a request is filed, and they can’t approve their own.
- You can’t approve your own request, unless you’re an owner and give a reason. The request records that you approved it yourself, and the organization’s other admins and owners get an email with your reason.
- Only people approve. No API key, service account, or CI token can approve or reject a request, or turn a track’s protection on or off, whatever its permissions.
- Decided requests stay listed under Decided with who decided and their comment, and every request and decision is in the audit log.
Deployment freezes
Section titled “Deployment freezes”A deployment freeze window is a period when no patch can be put in front of production users, such as a holiday change freeze or every weekend. While a window is active, Shorebird refuses:
- On a protected track: approving a request. A patch sent to the track still files its request, which waits for the window to end.
- On
stable, when it isn’t protected: promoting a patch to it, includingshorebird patch --track=stable, rolling a patch forward on it, raising a patch’s rollout percentage on it, and setting a rollout schedule on it.
A timed rollout schedule on stable or a protected track holds at its current
step while a window is active, and moves on once it ends.
Other changes still work during a freeze, so an incident can always be undone:
rolling a patch back, moving a patch off the track, and patches on tracks that
are neither stable nor protected, such as staging.
A refused change fails with the error code deployment_freeze_active. Its
message names the window and when it ends:
To ship during a freeze, wait for the window to end, remove it, or override it.
A refused shorebird patch has still uploaded the patch. Once the window ends,
promote that patch
instead of running shorebird patch again, which would create a new one. It’s
the newest patch marked [no track] in
shorebird patches list --release-version <version>.
Add a freeze
Section titled “Add a freeze”A window covers either every app in your enterprise, or one app. Both are managed on a Deployment freeze windows card in the Shorebird console:
- Enterprise-wide windows apply to every app in every organization of the enterprise. Enterprise Owners and Admins manage them: open Enterprise in the sidebar, then its Security tab.
- App windows apply to one app. Open the app’s Settings tab. Anyone who can protect its tracks can add and remove them: an admin or owner of the organization, or an app collaborator with the Admin role. The card also lists the enterprise-wide windows that apply to the app, marked Enterprise; those can only be removed from the enterprise’s Security tab.
Windows apply only while the organization is part of the enterprise. An organization that leaves keeps its protected tracks, but its freeze windows stop applying. On other plans, the app’s card has no Add freeze window button.
To add a window, click Add freeze window, give it a Name, and pick a Schedule:
- Fixed window: Starts at (UTC) and Ends at (UTC), as ISO 8601
timestamps such as
2026-12-24T00:00Zand2026-12-26T00:00Z. The end must be after the start. - Weekly recurring: a Day of week, a Start time (24-hour) in
HH:MM, a Duration (minutes), and a Timezone, an IANA name such asUTCorAmerica/New_York. The start time is local wall-clock time in that zone, so the window starts at the same local time across daylight saving changes. A window can last up to 10,079 minutes, one minute short of a week, and can run past the end of the week: a window starting Friday at 17:00 for 3,840 minutes runs until Monday at 09:00.
Each window on the card shows its name, a Fixed or Weekly badge, and its schedule. To remove one, open its options menu, choose Remove, and confirm with Remove. Production changes are no longer blocked during that window.
Override a freeze
Section titled “Override a freeze”An owner of the app’s organization can ship through an active window by giving a
reason of at least 10 characters. So can an enterprise Owner or Admin who can
also promote patches to stable in the app. It has to be their own sign-in,
from shorebird login or the console. An API key or a service account can’t
override a freeze, whatever its permissions.
The console and the CLI’s own commands have no option for it yet. Send the
request with shorebird api and add break_glass_reason to
the request body. The public API’s promote, roll-forward and rollout endpoints
accept it for a patch going to stable, or for raising its rollout percentage
there, when stable isn’t protected:
PATCH_ID, CHANNEL_ID and RELEASE_ID are IDs, not the patch number or the
track’s name. List them with shorebird api /apps/APP_ID/channels,
shorebird api /apps/APP_ID/releases and
shorebird api /apps/APP_ID/releases/RELEASE_ID/patches.
PERCENTAGE can’t be below the patch’s current percentage, since rollouts only
go up, and only a higher one needs the reason. Setting a percentage ends any
timed rollout schedule the patch was on. -F sends only a whole number as a
number. For a fraction such as 12.5, pass the whole body as JSON with
--input, reason included: with --input, -f and -F fields go in the URL,
where the reason isn’t read.
The rollout call sets one platform’s patch, the one in the path, so repeat it
with each platform’s PATCH_ID.
On a protected track, a patch or a higher rollout percentage goes out only through an approval request, and approving one can’t override a freeze from the console, the CLI’s own commands or the public API.
The organization’s other admins and owners get an email about each override.
Adding, removing, and overriding a window are recorded in the audit log.