Shorebird is a powerful tool and it's easy to overuse. The first time I set it up I wanted to push patches for everything — every bug fix, every copy change, every small tweak. Six months in, my release history was a mess of patches layered on patches and I couldn't remember which users were running which version. I pulled back hard, and now I have a simple rule that's worked for every app since.
The rule: patches are for emergencies, releases are for everything else.
What counts as an emergency
Three things:
- Crashes that hit real users. A null check you missed, a type mismatch in a JSON parser, anything that made it past your tests into production and is now breaking sessions. Push a patch.
- Broken content. A typo in a legal disclaimer, a wrong price in your paywall copy, a feature flag that went out enabled when it shouldn't have. Push a patch.
- A security bug. Leaked API key in a log line, a missing auth check, exposed data in a response. Push a patch, then file a CVE if you need to.
Everything else is a release. New features, redesigned screens, performance improvements, dependency bumps, analytics events, bigger refactors — none of these are emergencies. They go through the normal store review cycle.
Why I don't ship features as patches
Two reasons, both painful.
It fragments your user base in a way that's hard to reason about. If you release v1.0, then patch it to add a feature, then release v1.1 with a different set of changes, you now have users running v1.0+patch1 and v1.1+patch0 and the two codebases can diverge in subtle ways. Bug reports become impossible to triage because you don't know which combination the user is on.
It trains you to skip real releases. Every patch you push makes the next patch easier. Every full release you put off accumulates into a bigger, scarier release later. Six months of patches turns into a terrifying v2.0 that nobody wants to cut because the diff is huge. I've watched this happen on a team and I don't want to live through it again.
The release cadence I actually run
- Full store releases: every 2-4 weeks, whatever features landed in that window. Goes through normal review, lands on the standard rollout schedule.
- Patches: only when something breaks between releases. On a good quarter I push zero patches.
- Hotfix budget: I give myself two patches per release before I consider it a problem worth retrospecting. Three patches means I shipped the release too fast or skipped testing.
If you find yourself pushing more than two patches per release, something earlier in your process is broken. It's usually test coverage, manual QA, or a CI check that's missing.
What patches are great for that isn't an emergency
A few legitimate non-emergency uses:
- Removing a feature in a hurry. Something went live that shouldn't have — a broken A/B test, a premature announcement, a half-finished experiment. Patch it out. This isn't technically an emergency but it's close enough.
- Remote config fallbacks. If you use Supabase or Firebase Remote Config and the backend goes down, a patch lets you swap to hardcoded fallback values.
- Time-sensitive content. A launch announcement that needs to match an external date. This is rare but valid.
The decision tree
Use this:
- Is it breaking users right now? → Patch
- Will it take more than a few days to reach users via the normal release cycle? → Still ask: will it break users?
- Is it a new feature, or a refactor, or an improvement? → Release
- Are you reaching for a patch because it's faster than testing a release properly? → Slow down, ship a release
That's it. The whole rule for when to use Shorebird.
What to pair this with
- Code Push — the actual commands and the patch lifecycle.
- Hotfix project — walk through the patch flow end-to-end on a real app.
- Publish to Google Play and Publish to App Store — the full-release side of the equation.
Shorebird earns its place in your stack when you treat it as an emergency lane. Treat it as your primary ship mechanism and you'll outgrow it in a quarter.