DEV Community

Mostafa Abdelsalam
Mostafa Abdelsalam

Posted on Originally published at mostafaabdelsalam.dev AI-assisted

Shorebird in production: Flutter OTA updates without store review

Shorebird lets a Flutter app download a patch to its Dart code and apply it on the next launch, so a bug fix reaches users in minutes instead of waiting on store review. I added it to Qirat, my gold price tracker on iOS and Android, in April 2026. This is how it works, how I use it, and where it bites.

Why I added it

To stop waiting on review for changes that do not need one. In Qirat that means three things: a UI change, a new section that needs no new packages, and the kind of bug a numbers app gets, where a calculation comes out wrong.

Qirat shows gold prices and what your holdings are worth. When a number on that screen is wrong, the fix is usually one line of Dart, and store review is the slowest part of shipping it.

How it works

There are two commands that matter, and the difference between them is the whole mental model.

A release is a full build that goes through the store as usual. shorebird release is a drop-in replacement for flutter build: it produces the .aab or .ipa, and it uploads the compiled Dart code to Shorebird as the baseline for future patches.

shorebird init
shorebird release android
shorebird release ios
Enter fullscreen mode Exit fullscreen mode

You still upload the artifact to Google Play and App Store Connect yourself. Shorebird does not touch store submission.

A patch is a diff against one specific release. It never goes through the store.

shorebird patch --platforms=android,ios --release-version=latest
Enter fullscreen mode Exit fullscreen mode

On the device, the app checks for a patch on startup, downloads it on a background thread, and applies it the next time the process restarts. If the request fails, it tries again on the next launch.

What a patch can and cannot change

A patch changes Dart code. That covers most real bugs: a null check, a wrong calculation, a broken layout, a bad API mapping.

A patch cannot change:

  • Native code: Kotlin, Swift, or build configuration.
  • Assets added or removed in pubspec.yaml.
  • The Flutter version. The patch must be built with the same one as the release.
  • A plugin with native code that was not already in the release binary.

The CLI warns you when it sees native or asset differences and blocks the patch unless you pass --allow-native-diffs or --allow-asset-diffs. Treat that warning as a stop sign. If the fix needs native changes, it needs a store release.

My workflow

For Qirat it is as simple as it gets: I run the CLI by hand from my machine and patch straight to the stable track. No CI, no staging step. I also left updates on the default behaviour, so there is no in-app prompt; the patch lands on the next cold start.

That fits a solo app with small patches. It is not best practice. With a team or a larger user base, the safer path is to patch to the staging track, check it on a real device, then promote:

shorebird patch android --track=staging
shorebird patches promote --release-version 1.4.0+12 --patch-number 1
Enter fullscreen mode Exit fullscreen mode

And if a patch is bad:

shorebird patches rollback --release-version 1.4.0+12 --patch-number 1
Enter fullscreen mode Exit fullscreen mode

A patch that mattered

A bug in how Qirat calculated the price gap. A wrong number in an app people open to check prices is the worst kind of bug to leave sitting.

From noticing it to the fix being live took a few minutes: correct the calculation, run one patch command, done. Through the stores, the same one-line fix would have waited on review twice, once per platform.

Gotchas

The patch lands on the next restart, not instantly. The first launch after you publish only downloads it. A user who never closes the app keeps the old code. If a fix is urgent, use the shorebird_code_push package to check for an update in-app and prompt for a restart.

Patches are tied to one release. A patch for version 1.4.0 does nothing for users still on 1.3.0. If you have several store versions in the wild, you patch each one.

On iOS, changed code runs slower. Unchanged code runs on the CPU as normal. Code that the patch changed or added runs in a Dart interpreter. For a bug fix nobody notices. I would not patch a hot loop or an animation-heavy screen and assume the same performance.

The Flutter version is frozen per release. A patch has to use the same Flutter version as the release it targets. If your main branch has moved to a newer Flutter since, the fix has to be written against the old one.

Package changes mean a store release. This is the one I plan around. A patch cannot add a plugin with native code, so any change that touches packages goes through the stores, and everything else is a candidate for a patch.

Shorebird and Remote Config are different tools

Qirat uses both, and they do not overlap.

Firebase Remote Config flips switches that already exist in the shipped code: show this feature, hide these ads on this platform. It is instant and needs no restart, but it can only choose between paths you wrote in advance.

Shorebird changes the code itself. It fixes the bug you did not see coming.

My rule: if I can predict the decision, it is a Remote Config flag. If I cannot, it is a patch.

Is it allowed on the stores?

Yes, within limits. Apple permits downloading interpreted code as long as it does not change the primary purpose of the app or bypass security features, and Shorebird runs patched code through an interpreter on iOS for that reason. Google Play restricts apps from updating themselves outside Play, with an exception for code that runs in an interpreter or virtual machine.

The practical line: ship fixes and small improvements as patches. Do not use a patch to turn the app into something the reviewer never saw.

Is it worth it?

For an app like Qirat, yes. It is a solo app, it is all numbers, and it gets frequent small changes. Shorebird took review time out of exactly those changes.

The cost is one more step in the release process and a set of limits you have to remember: Dart only, one release at a time, next restart. If most of your changes touch native code or packages, you will get much less out of it.

Quick answers

Does Shorebird work with the App Store and Google Play? Yes. You still release through the stores; patches are delivered separately and comply with both stores' rules on interpreted code.

Can Shorebird update native code or assets? No. Patches change Dart code only.

When does a user get the patch? The app downloads it in the background on launch and applies it on the next restart.

Does it slow the app down? Not on Android. On iOS only the changed code runs slower, because it runs in an interpreter.


Originally published on mostafaabdelsalam.dev. I'm Mostafa Abdelsalam, a founding engineer and solopreneur: I build my own Flutter apps and help businesses grow theirs. More on how Qirat is built in the case study.

Top comments (0)