Imagine you’ve just launched a major feature. Your app is climbing the charts, but then the first bug report arrives. It’s a critical payment validation error. The fix is a single line of Dart code, but now you face the dreaded app store review queue, hours, maybe days of delay, all while your users and revenue are impacted.
What if you could bypass the store and deliver that fix directly to your users in minutes?
This is the power Shorebird brings to your Flutter workflow. It’s not just about speed, it’s about control, reliability, and delivering a superior user experience.
This guide will take you from a novice to a pro, covering everything from setting up Shorebird to implementing robust, production-grade update strategies with the upgrader
package.
Table of Contents:
Prerequisites
Before you dive in, make sure you have the following knowledge and tools set up. This will help you follow the guide smoothly and avoid common setup issues.
Knowledge and Skills
Fundamental Flutter knowledge: You should be comfortable creating Flutter projects, managing packages with
pubspec.yaml
, and understanding the basic widget lifecycle. This guide assumes you have an existing Flutter application to work with.Command-line proficiency: You need to be comfortable using a terminal (like Terminal on macOS/Linux or PowerShell on Windows), as Shorebird is primarily a Command-Line Interface (CLI) tool. This includes navigating directories and executing commands.
Basic Git and version control: Understanding concepts like commits, branches (
main
,hotfix
), and checking out code is crucial for managing releases, creating patches from specific code states, and implementing rollback strategies.
Tools and Environment
A working Flutter development environment:
The latest stable version of the Flutter SDK.
An IDE configured for Flutter, such as VS Code or Android Studio.
A Shorebird account:
- You’ll need to sign up for a free account on the Shorebird website. The
shorebird login
command requires this.
- You’ll need to sign up for a free account on the Shorebird website. The
Platform-Specific Build Tools:
For Android:
An installation of Android Studio and the corresponding Android SDK.
A configured signing keystore (
key.jks
) andkey.properties
file for your project. Shorebird needs this to create signed, production-ready release builds (AABs).
For iOS:
A macOS computer with Xcode installed. Building for iOS is not possible on Windows or Linux.
An active Apple Developer Program membership is required to code sign and release iOS apps.
Optional (but Recommended for the Full Strategy)
A Firebase project: To implement the complete, real-world strategy involving forced updates and remote feature flags, you will need:
A Firebase project linked to your Flutter app.
The Firebase Remote Config service enabled.
The
firebase_core
andfirebase_remote_config
packages added to yourpubspec.yaml
.
What is Shorebird?
Shorebird is a code push service specifically designed for Flutter applications. It allows developers to deliver small, critical bug fixes and even new features directly to users’ devices, bypassing the traditional app store review process. In essence, it enables “over-the-air” (OTA) updates for Flutter apps.
This means that instead of waiting hours or days for app store approval for a simple fix, you can deploy the change almost instantly, ensuring a much faster response to issues, reduced downtime for users, and minimal impact on revenue. It gives you greater control over your app’s deployment lifecycle and helps maintain a smoother, more reliable user experience.
1. The “Why”: When to Patch vs. When to Release
Before diving into the “how,” it’s crucial to understand the “when/why.” Not all updates are created equal. Using the right tool for the job is key to a stable and efficient development cycle.
Use shorebird patch
for:
Critical bug fixes: Logic errors in your Dart code (for example, calculation mistakes, null pointer exceptions, incorrect state management).
Minor UI tweaks: Changing colors, text, or layout logic without adding new assets.
Feature flag toggles: Pushing a code change that enables or disables a feature you’ve already built and deployed.
Performance improvements: Optimizing algorithms or Dart-level rendering logic.
Use a full store release for:
Native code changes: Any modifications to the
android
orios
directories.Plugin/dependency updates: Adding a new package or upgrading an existing one in
pubspec.yaml
, as this often changes native code or includes pre-compiled binaries.Asset changes: Adding new images, fonts, JSON files, or any other assets.
Major feature releases: When the app’s functionality or UI changes significantly, it’s best practice (and often required by store policies) to go through a full review.
Think of it this way: if the change is only in your .dart
files and doesn’t touch pubspec.yaml
, it’s likely patchable.
2. Getting Started: Installation & Project Setup
Let’s get your environment and project ready for Shorebird.
Step 1: Install the Shorebird CLI
Open your terminal and run the official installation script:
curl https://raw.githubusercontent.com/shorebirdtech/shorebird/main/install.sh -sSf | bash
Step 2: Add Shorebird to your PATH
To use the shorebird
command from anywhere, add it to your shell’s configuration file (.zshrc
, .bashrc
, .bash_profile
, and so on).
export PATH="$HOME/.shorebird/bin:$PATH"
Restart your terminal or run source ~/.zshrc
(or your respective file) for the change to take effect.
Step 3: Verify and Log In
Confirm the installation was successful and log in to your Shorebird account.
shorebird --version
shorebird login
This will open a browser window to authenticate your CLI with the Shorebird service.
Step 4: Initialize Shorebird in Your Flutter Project
Navigate to the root directory of your Flutter project and run:
shorebird init
This command is your project’s entry point into the Shorebird ecosystem. Here’s what it does under the hood:
Creates
shorebird.yaml
: This file stores your unique app ID. Commit this to version control.Modifies
pubspec.yaml
: It automatically adds theshorebird_code_push
package, which is necessary for the app to communicate with Shorebird’s servers.Updates
.gitignore
: Adds the.shorebird/
directory to prevent temporary build artifacts from being committed.
3. The Core Workflow: Releasing and Patching
Shorebird’s workflow is built on a simple concept: you create a base release, and then you apply patches to it.
Step 1: Create a Full Release
Before you can patch anything, you need a full version of your app built with Shorebird. This release will be submitted to the App Store and Play Store.
# For Android
shorebird release android
# For iOS
shorebird release ios
This command compiles your app, uploads the necessary symbols to Shorebird’s servers so it can build patches later, and generates the release artifact (AAB/IPA) for you to upload to the stores.
Step 2: Create and Publish a Patch
After fixing a bug or making a tweak in your Dart code, you can create a patch. Shorebird will compare your changes against the original release and create a small, efficient binary diff.
# Patch the latest Android release
shorebird patch android
# Patch the latest iOS release
shorebird patch ios
This patch is immediately available to users who have the corresponding base release installed.
Step 3: The User Experience
When you push a patch, the process is designed to be seamless:
Silent download: On the next app launch, the
shorebird_code_push
SDK checks for a new patch. If one is found, it downloads silently in the background.Applied on next relaunch: The downloaded patch is staged and automatically applied the next time the user closes and re-opens the app. This ensures their current session is not interrupted.
4. Taking Control: In-App Update Logic in Flutter
For a more controlled experience, you can use the shorebird_code_push
package to manage the update process within your app.
import 'package:shorebird_code_push/shorebird_code_push.dart';
final _shorebirdCodePush = ShorebirdCodePush();
// Check for a new patch on app start.
void checkForUpdate() async {
// Check if a new patch is available.
final isUpdateAvailable = await _shorebirdCodePush.isNewPatchAvailableForDownload();
if (isUpdateAvailable) {
// Optionally, you can show a dialog to the user here.
// e.g., "A quick update is available. It will be applied on next restart."
// Download the new patch.
await _shorebirdCodePush.downloadUpdateIfAvailable();
}
}
// For critical updates, you can force an immediate restart.
void forceRestart() async {
// Make sure a patch is downloaded and ready to be installed.
if (await _shorebirdCodePush.isNewPatchReadyToInstall()) {
// This will force the app to close and restart with the new patch.
// Use with caution, as it's a disruptive user experience.
await _shorebirdCodePush.installUpdateAndRestart();
}
}
Call checkForUpdate()
in your main()
function or the initState
of your primary screen.
5. The Nuclear Option: Forcing Updates with upgrader
Sometimes, a Shorebird patch isn’t enough. For critical updates that involve native code, new assets, or if you need to ensure every single user is on the latest version right now, you need a blocking update screen. The upgrader
package is perfect for this.
Step 1: Add the Dependency
dependencies:
upgrader: ^7.0.0
Step 2: Implement the Blocking UI
Wrap your MaterialApp
with the UpgradeAlert
widget to create a blocking dialog that cannot be dismissed.
import 'package:flutter/material.dart';
import 'package:upgrader/upgrader.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// This configuration creates a blocking "must-update" screen.
final upgrader = Upgrader(
showIgnore: false,
showLater: false,
canDismissDialog: false,
dialogStyle: UpgradeDialogStyle.material,
shouldPopScope: () => false, // Prevents back navigation
);
return MaterialApp(
home: UpgradeAlert(
upgrader: upgrader,
child: HomeScreen(), // Your app's main screen
),
);
}
}
6. Real-World Playbook: Combining Shorebird, Upgrader, and Remote Config
Here’s how to tie everything together for a bulletproof update strategy. Let’s use Firebase Remote Config to act as our remote “kill switch.”
Scenario: Version 1.2.0
of your app has a critical payment bug.
The Playbook:
Fix the bug: Correct the error in your Dart code.
Push a Shorebird patch:
shorebird patch android --release-version 1.2.0+10 # Use --release-version to target a specific build
This delivers the fix to active users quickly and silently.
Set a remote flag: In your Firebase Remote Config console, create a parameter like
force_update_for_version
and set its value to"1.2.0"
.Implement logic in your app: On app start, check this flag before showing your main UI.
import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:package_info_plus/package_info_plus.dart'; Future<void> main() async { // ... initialization code ... // Get current app version final packageInfo = await PackageInfo.fromPlatform(); final currentVersion = packageInfo.version; // Fetch remote config final remoteConfig = FirebaseRemoteConfig.instance; await remoteConfig.fetchAndActivate(); final forceUpdateVersion = remoteConfig.getString('force_update_for_version'); // Check if this version is flagged for a forced update if (currentVersion == forceUpdateVersion) { // This is a "bad" version. Show the blocking update screen. runApp(ForcedUpdateApp()); } else { // This version is fine. Run the normal app and check for a Shorebird patch. checkForUpdate(); // Your Shorebird check function runApp(MyApp()); } } // A simple app that only shows the upgrader screen. class ForcedUpdateApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: UpgradeAlert( child: Scaffold(body: Center(child: Text('Checking for updates...'))), ), ); } }
This dual strategy ensures that users who haven’t received the Shorebird patch yet are still blocked from using the buggy version and are directed to the store.
7. Production-Grade Best Practices
Before you hit “patch” in production, you should treat Shorebird like any other release pipeline: test the build, roll it out in waves, keep an eye on crash metrics, and automate the boring parts. Here are some best practices to follow:
First, always test patches. Use shorebird preview
to test your patch on a local device or emulator before deploying it to users.
shorebird preview
Use staged rollouts with channels. Don’t push a critical patch to 100% of users at once. Shorebird’s “channels” feature lets you deploy to a staging
audience first.
# Push patch to internal testers
shorebird patch android --channel=staging
# After verification, promote it to all users
shorebird promote --channel=staging --release-version 1.2.0+10
You should also have a rollback plan if a patch makes things worse. In this case, the fastest way to fix it is to patch forward. Check out the last known-good commit from Git and run shorebird patch
again. This new patch will overwrite the bad one.
And make sure you monitor everything. To do this, you can use tools like Firebase Crashlytics or Sentry to monitor crash rates and app stability after a patch is released.
Finally, it’s helpful to automate with CI/CD, and you can integrate Shorebird right into your CI/CD pipeline (for example, GitHub Actions). Store your SHOREBIRD_TOKEN
as a secret and use commands like shorebird patch android --release-version <version> --force
to automate deployments.
8. Security, Cost, and Limitations
There are some other things you should keep in mind when using Shorebird.
First, all communication with Shorebird’s servers is over TLS. Patches are cryptographically signed, and the shorebird_code_push
SDK verifies this signature before applying an update, ensuring it hasn’t been tampered with.
Second, Shorebird operates on a freemium model with a generous free tier. Paid plans are based on Monthly Active Users (MAU) and unlock team features. You can check the official pricing page for current details.
Also, keep in mind that there are some limitations that we’ve already touched on a bit: for example, Shorebird only patches Dart code. You can’t update native plugins, add/change assets, or modify native code (android
/ios
folders) with a patch. These changes always require a full store release.
Wrapping Up
Shorebird is a transformative tool for any serious Flutter developer. It moves the release process from a monolithic, slow cycle to a dynamic, responsive one.
By combining Shorebird’s rapid patching with a robust forced-update strategy using upgrader
and Remote Config, you gain unprecedented control over your production application. You can fix bugs in minutes, mitigate risks, and keep your users happy – all without waiting for the app store.
References
1. Shorebird
2. Upgrader Package
3. Supporting Tools & Concepts
Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & MoreÂ