You are here: Home > App Distribution > Distribute > Rolling Back a Release

Reverting a problematic release safely

Revert a problematic Build in Applivery App Distribution by rebuilding your stable version with a higher version identifier and moving the Publication tag to it.

7 min read

TL;DR

Rebuild your last stable version with a higher version identifier, upload it, and move the ring's tag to the new Build. Remember to lower the SDK forced update threshold if you use one.

You shipped a release, something is wrong with it, and you need people back on the version that worked. The instinct is to put the previous Build back into circulation — but that is not enough on its own, because whether a device accepts an older version is decided by the operating system, not by Applivery.

The reliable way to revert a release is to ship forward: take the code of the last version that worked, rebuild it with a higher version identifier than the problematic Build, and distribute that. The code goes backwards; the version number goes forwards. To the device it is an ordinary update, which is exactly why it installs.

Note

This approach works on every platform Applivery distributes to. Some platforms would also accept a straight downgrade, but the roll-forward is the one procedure that is safe everywhere — so it is the one worth standardizing on.

Why you cannot simply re-serve the old Build

On Android, the system package manager refuses to install a package whose versionCode is lower than the one already installed. The install fails with INSTALL_FAILED_VERSION_DOWNGRADE. Android's manifest documentation states the rule plainly: each successive version must carry a higher number.

So if you re-tag the old Build, anyone who already installed the problematic version stays stuck on it. The people you most need to fix are precisely the ones the old Build cannot reach.

Rebuilding with a higher version identifier sidesteps this entirely.

The version identifier on each platform

Applivery reads version information from the package you upload — it is not something you can set in the Dashboard or pass to the API. It has to be set at build time.

Platform What to increase Format
Android versionCode in your build configuration Integer — 201
iOS / macOS CFBundleVersion in the app's Info.plist One to three period-separated integers — 2.0.1
Windows (MSIX / APPX) Version in AppxManifest.xml Four-part version
Custom platforms packageVersion at upload time Manual
Warning

Apple's CFBundleVersion is not a plain integer like Android's versionCode. It is a string of up to three period-separated integers, so "add one" is not meaningful on its own. If the problematic Build is 2.0.0, your rollback Build should be 2.0.1 or higher. See Apple's CFBundleVersion reference.

The user-facing version — versionName on Android, CFBundleShortVersionString on Apple — has no technical rules. Use it to make the situation legible: keeping 1.9 makes clear which code is running, while 2.0.1 makes clear it is newer than the release it replaces. Pick whichever your users will find less confusing.

The procedure

1
Identify the last known-good version

Find the source of the version you are reverting to, and confirm the version identifier of the problematic Build so you know what you have to exceed.

2
Rebuild it with a higher version identifier

Same code, new version identifier — higher than the problematic Build. This happens in your project configuration or CI pipeline, not in Applivery.

3
Upload the rebuilt Build

Give it a versionName that makes its purpose obvious, such as v1.9 (rollback). Wait for processing to finish before continuing.

4
Remove the tag from the problematic Build

Open the problematic Build and remove the affected Publication's tag. It stops being served immediately.

5
Add the tag to the rollback Build

The Publication now serves the rollback Build, and devices see it as an available update.

6
Lower the forced update threshold, if you use one

See Watch out for forced updates below. Skipping this step can lock users out of the app entirely.

Worked example

Problem:
  Build v2.0  ·  versionCode 200  ·  live in production  ·  defect found

Rollback:
  Rebuild v1.9 source  ·  versionCode 201  (higher than 200)
  Upload, then move the production tag from Build 200 to Build 201

A device sitting on 200 receives 201, treats it as an update, and installs it — but the code it ends up running is the stable 1.9 logic.

From the API

Both tag changes use PUT – Update a Build.

Warning

The tags field replaces the entire array. Send every tag the Build should keep, not just the one you are changing.

# 1. Stop serving the problematic Build
curl 'https://api.applivery.io/v1/integrations/builds/BUILD_ID_PROBLEM' \
  -X PUT \
  -H 'Authorization: Bearer YOUR_APP_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ "tags": [] }'

# 2. Point the ring at the rollback Build
curl 'https://api.applivery.io/v1/integrations/builds/BUILD_ID_ROLLBACK' \
  -X PUT \
  -H 'Authorization: Bearer YOUR_APP_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ "tags": ["ring-production"] }'

The Workspace API equivalent is PUT https://api.applivery.io/v1/organizations/ORG_ID/apps/APP_ID/builds/BUILD_ID with a Service Account token.

If you use progressive deployment, roll back one ring at a time, starting with the ring where the problem appeared.

Apple devices behave differently depending on how the app was installed

Apple does not document what happens when you install an app whose CFBundleVersion is lower than the one already on the device, so we tested it ourselves. On iOS 26.5, the same app on the same device behaved in two opposite ways depending on the delivery path:

How the app reaches the device Installing an older Build
App Distribution — user installs from the Enterprise Store The older Build installs normally
Device Management — Build assigned through MDM The device keeps the newer version
Warning

When an older Build is assigned through Device Management, the device does not downgrade — and it does not report an error either. The command is accepted, nothing fails, and the newer version simply stays installed. If you are rolling back this way, the Dashboard will not tell you that nothing happened. Verify the installed version before assuming devices are fixed.

The practical consequence:

  • If you distribute through the Enterprise Store, you can roll back by simply moving the tag back to the previous Build. No rebuild needed.

  • If you deploy through Device Management, moving the tag is not enough. You have to rebuild with a higher version identifier, exactly as described above.

Note

This behavior is not documented by Apple, which means it is not guaranteed to stay the same in future iOS releases. Our test covered a supervised device enrolled through Apple Business. Treat the Enterprise Store shortcut as a convenience, not as something to build automation around — the roll-forward procedure is the one that keeps working regardless.

Watch out for forced updates

If your App embeds the Applivery SDK with forced updates enabled, there is a trap here worth knowing about.

Forced updates block app usage when the installed version falls below a minimum version threshold you configure in the Dashboard. If that threshold is still set to the problematic release, your rollback Build sits below it — and every user who installs it gets locked out of the app by the very fix you shipped.

Lower the threshold as part of the rollback, not after it.

One thing works in your favour: the SDK always updates to the most recent Build available for the App, matching only bundle ID or package name. It goes by recency, not by version number, so a freshly uploaded rollback Build is picked up as the update regardless of where its version sits.

Note

The SDK does not respect Publication filters, groups, or audiences. If you need the rollback confined to one ring, be aware that SDK-driven updates do not honour that boundary.

After the rollback

  • Keep the problematic Build. Do not delete it — you will want it to reproduce the defect. Untagging is enough to take it out of circulation.

  • Mind the version numbers going forward. Your next real release has to exceed the rollback Build, not the problematic one. If the rollback was 201, the fixed release starts at 202.

  • Let people know. If the Publication notifies its audience, an explicit message speeds things up — users who postponed the previous update may otherwise ignore this one too.

Tip

The cleanest way to avoid ever needing this is to catch the defect in a small ring first. See Progressive Deployment with Tags.

Key Takeaways

  • A rollback ships forward — the code is older but the version identifier is higher.
  • Applivery reads version information from the package; it cannot be set at upload time.
  • Move the tag off the problematic Build so the Publication stops serving it.
  • Lower the SDK forced-update minimum version, or users will be locked out.

Rebuild your last stable version with a version identifier higher than the problematic Build, upload it, and move the Publication's tag from the problematic Build to the new one.

It depends on the platform. Android devices refuse a lower version code outright, and Apple devices ignore the change when the app is managed through Device Management. Rebuilding with a higher version identifier is the only approach that works everywhere.

Because the fix ships as a new, higher-numbered release even though its code is older. To the device it looks like an update, which is what makes it install.

No. Only the internal version identifier has to increase. You can keep the user-facing version name as it was, or mark it clearly as a rollback.

If your SDK forced-update minimum version is still set above the rollback version, users will be blocked out of the app. Lower the threshold before or as part of the rollback.

The SDK always updates to the most recent Build available for the App, matching bundle ID or package name — it goes by recency, not by version number.

No. Applivery reads the version information from the package you upload. It has to be set at build time, in your project configuration.

Remove the Publication's tag from it. A Build with no matching tag is no longer served by that Publication.

Was this page helpful?

Last updated: July 30, 2026