---
title: "Roll back a Patch"
description: "Stop a bad patch from reaching more devices, what devices that already have it do, and how to roll a patch forward again."
---

If you discover that a live patch has a bug, Shorebird supports patch roll back. When a patch is rolled back, it is remotely uninstalled from end users’ devices and replaced by either the previous patch or the base release if no previous patch is available.

A rollback is not permanent. If you roll a patch back and then decide you want it after all, you can [roll it forward](#roll-a-patch-forward) to make it the active patch again.

If your app saves state to disk, the code that runs after a rollback reads what the rolled-back patch wrote. [Shipping BLoC changes as a patch](/flutter-concepts/state-management/advanced/#shipping-bloc-changes-as-a-patch) shows how to keep saved state readable in both directions.

If an iOS app crashes once a patch installs, the release’s Flutter version may be the cause; see [App crashes after a patch installs](/code-push/troubleshooting/#app-crashes-after-a-patch-installs).

Emergency Quick-Rollback

If a broken patch is live in production, roll it back immediately using one of these options:

* **Option A (CLI - Fastest)**: Run the following command in your terminal. It needs Shorebird 1.6.120 or newer. On an older CLI, use Option B, or run `shorebird upgrade` first:

  ```
  shorebird patches rollback --release-version <RELEASE_VERSION> --patch-number <PATCH_NUMBER>
  ```

* **Option B (Console)**: Go to the [Shorebird Console](https://console.shorebird.dev/), select your release, click the three-dots icon on the patch row, and select **Rollback**.

Note

Rollback works on every release built with Flutter 3.24.0 or newer, the oldest version Shorebird creates releases with today. Some older releases you can still patch, built with a Shorebird Flutter from before rollback support arrived in July 2024 (for example iOS releases on Flutter 3.22.2), can’t apply a rollback. On those releases the Console offers [Deactivate](#releases-that-cant-roll-back) instead of **Rollback**. `shorebird patches rollback` doesn’t check for this: on those releases it stops new devices getting the patch, but devices that already have it keep it, so ship a fixed patch as well.

[Watch the video: Roll back a patch](/videos/rollback-patch.mp4)

## Active and superseded patches

When a device checks in, Shorebird serves the highest-numbered patch on that device’s track that has not been rolled back. The Console shows that patch as active.

Apart from [Deactivate](#releases-that-cant-roll-back) on older releases, patches have no individual on/off switch. Publishing patch 3 outranks patch 2 without any action on patch 2:

* One patch is served per track at a time.
* Lower-numbered patches are superseded: devices aren’t served them while a higher-numbered patch is on the track.
* Rolling back the active patch moves devices to the next-highest patch on the track that has not been rolled back, or to the base release.

To return users to patch 1 while patch 3 is live, roll back patch 3 and patch 2. Leave patch 1 alone.

Note

Rolling back a superseded patch has no immediate effect, since devices are not served it. It removes that patch from the set devices can fall back to later.

### Releases that can’t roll back

On a release built with a Flutter version from before rollback support, the patch menu on a `stable` patch shows **Deactivate** instead of **Rollback**. New devices stop getting the deactivated patch and get the newest patch that isn’t deactivated. Devices that already have the patch keep it, so ship a fixed patch as well.

### Why the Console may still show old patches installing

Patch install events are reported the next time an app launches, which can be hours or days later. A patch that is no longer served can keep showing new install events during that window.

## How to roll back a patch

In the [Shorebird Console](https://console.shorebird.dev/), navigate to the release that contains the patch you want to roll back. On the right side of the patch row, click the “more” icon (three vertical dots) and select “Rollback”:

![The Shorebird Console showing a "roll back patch" button](/_astro/rollback_button.Kq0beFVB_1QlbJz.webp)

### Roll back from the CLI

As of Shorebird 1.6.120, you can also roll back a patch from the command line. Pass the release version and the patch number:

```
shorebird patches rollback --release-version 1.0.0+1 --patch-number 2
```

```
Patch 2 on release 1.0.0+1 has been rolled back.
ID:          42
Number:      2
Track:       stable
Rolled back: yes
```

Shorebird reads the app ID from `shorebird.yaml` in the current directory. To run the command from anywhere else, such as a CI job, pass `--app-id`. If your app uses [flavors](/code-push/guides/flavors/), pass `--flavor` to pick the right app ID.

If the patch is already rolled back, the command says so and exits successfully. Add `--require-change` to make it exit with an error instead, so a script can tell whether this run changed anything. Add the global `--json` flag for machine-readable output:

```
shorebird patches rollback --release-version 1.0.0+1 --patch-number 2 \
  --require-change --json
```

## What happens when a patch is rolled back?

Imagine a release with two patches:

![The Shorebird Console showing two patches, with patch 2 as the active patch](/_astro/rollback_patch2_active.CS5CUKij_Z1Edxbo.webp)

When a user downloads this release from the store, Shorebird will see that patch 2 is the latest available patch and download it.

If a problem is discovered with patch 2, it can be rolled back. The Console hides rolled back patches by default. With **Show rolled back and deactivated** turned on next to the Patches heading, it looks like this after a rollback:

![The Shorebird Console showing two patches, with patch 2 rolled back and patch 1 as the active patch](/_astro/rollback_patch2_rolled_back.BjQt0JMa_Hcnqo.webp)

Users who download the app from the store will now get patch 1 instead of patch 2. Users who already had patch 2 installed will be downgraded to patch 1.

Caution

A device only learns about a rollback when it checks for updates. With [`auto_update: false`](/code-push/shorebird-yaml/#auto_update) in `shorebird.yaml`, that happens only when your app calls `checkForUpdate()` or `update()`, so a patch that breaks your app before that call can’t be rolled back on those devices. See [Update Strategies](/code-push/update-strategies#manual).

### Under the hood

When a Shorebird app checks for new patches, the server includes in its response a list of rolled back patches. If the device has any rolled back patches installed, it deletes them and reverts to the last “good” patch, which will be visible the next time the app starts.

Note

If your app needs to download an older patch as part of a rollback, installing that patch counts against your plan’s patch installs for the billing period.

Once your organization reaches its patch install limit, Shorebird refuses patch checks, so devices don’t learn about the rollback. They keep the patch they have until the limit goes up or resets. See [Your organization reached its patch install limit](/code-push/troubleshooting/#your-organization-reached-its-patch-install-limit).

## Roll a patch forward

Rolling a patch forward is the opposite of rolling it back: it takes a patch you previously rolled back and makes it the active patch again. Use it when you roll back a patch and then determine it was not the cause of the problem, or when you have confirmed the patch is safe after all.

In the [Shorebird Console](https://console.shorebird.dev/), navigate to the release containing the rolled back patch. Rolled back patches are hidden by default, so turn on **Show rolled back and deactivated** next to the Patches heading. On the right side of the patch row, click the “more” icon (three vertical dots) and select “Roll Forward”:

![The Shorebird Console showing a "Roll Forward" option in the menu of a rolled back patch](/_astro/roll_forward_button.B4Pjrz8f_ZJgJYn.webp)

Confirm the dialog to roll the patch forward.

The **Roll Forward** action only appears on a patch that is currently rolled back. On a patch that is not rolled back, the same menu offers “Rollback” instead.

### Roll forward from the CLI

`shorebird patches rollforward` takes the same arguments as [`shorebird patches rollback`](#roll-back-from-the-cli), including `--app-id`, `--flavor`, `--require-change`, and `--json`:

```
shorebird patches rollforward --release-version 1.0.0+1 --patch-number 2
```

```
Patch 2 on release 1.0.0+1 has been rolled forward.
ID:          42
Number:      2
Track:       stable
Rolled back: no
```

If the patch isn’t rolled back, the command reports that it is already active and exits successfully, unless you pass `--require-change`.

### What happens when a patch is rolled forward?

The patch stops being reported as rolled back, so it becomes the active patch for its track again. Devices download it on their next update check and apply it the next time the app restarts, exactly as they would a newly published patch.

Note

Devices that were downgraded by the rollback have to download the patch again, and that counts against your plan’s patch installs for the billing period.

## Patch integrity and automatic rollback

Shorebird includes safety features to prevent needing to issue the manual rollback of a patch.

`shorebird patch` also generates a hash of your patch file which is stored separately from the patch and checked every time your patch is installed, or booted from on the user’s device.

Shorebird also [signs patches](/code-push/guides/patch-signing): releases made with Shorebird CLI 1.6.132 or later are signed by default with a key Shorebird manages for your organization, or you can sign with your own key. This uses the same cryptographic algorithms used in the Google and Apple app stores. A signed release includes a [public key](https://en.wikipedia.org/wiki/Public-key_cryptography) in your app bundle, and a patch’s signature is checked before it’s used, so your app never accepts a patch file that wasn’t signed with the matching private key.

Finally Shorebird’s [updater](https://github.com/shorebirdtech/updater) includes automatic on-device rollback. If for any reason a patch’s hash or signature does not match, the patch is discarded.

If a patch fails to load into the Dart runtime on Android or iOS, the device marks the patch “bad” and never tries to boot it again. Later launches boot the previous working patch still on the device, or your release’s original code if there isn’t one, until a newer patch has downloaded.

What happens on the launch that failed depends on the platform and the Flutter version the release was built with:

* **iOS, Flutter 3.47.0 or newer** (the default since Shorebird 1.6.118): that launch runs your release’s original code.
* **iOS, Flutter 3.47.4 or newer** (the default since Shorebird 1.6.122): that launch also checks for a newer patch if automatic updates are on. With `auto_update: false` in `shorebird.yaml`, the check happens when your app calls the updater.
* **Android, and iOS before Flutter 3.47.0**: the app closes on that launch, and the device records the failure when the app next starts.

On macOS, Windows and Linux, the same mark-bad behavior needs Flutter 3.47.8 or newer (the default since Shorebird 1.6.133). On older versions, a Windows or Linux app whose patch fails to load doesn’t start, on every launch, until it’s reinstalled. A macOS app runs your release’s original code but keeps the patch and tries it again on every launch.

The previous patch file is always kept on disk until at least one successful boot is made of the next patch, after which a patch file is automatically cleaned up from the user’s device to minimize disk usage.

All code which implements these integrity measures is of course open source and available for review on [GitHub](https://github.com/shorebirdtech/). An overview of Shorebird’s code locations is available under [System Architecture](/code-push/system-architecture).

## Related

[Patch Signing](/code-push/guides/patch-signing)Cryptographically sign your patches for added security.

[Security Policies](https://handbook.shorebird.dev/security/)Shorebird's public security policies and compliance.

[System Architecture](/code-push/system-architecture)Overview of Shorebird's components and source code.
