OTA Updates
Mach-hosted React Native updates and customer-owned Shorebird for Flutter.
Mach chooses the OTA provider by framework. Expo and bare React Native use Mach-hosted expo-updates. Flutter commands delegate releases and patches directly to the customer's Shorebird account; Mach never stores SHOREBIRD_TOKEN.
Quick Start
Configure OTA
mach ota setup
mach ota verify
After the first setup, create and install one new native build before publishing OTA updates. The update URL and runtime are embedded in the native binary, so an older installed build cannot discover Mach OTA.
Publish
mach ota publish --channel production --platform all --message "Fix checkout screen"
Operate
mach ota list
mach ota rollback --update-id <updateId>
mach ota promote --update-id <updateId>
Flutter with Shorebird
Setup initializes shorebird.yaml and stores only non-secret provider metadata. Interactive machines may use an existing Shorebird login; CI reads SHOREBIRD_TOKEN from its secret environment. Create that API key in Shorebird Console → Account → API Keys; the older login:ci flow is deprecated. Create a base release for native or asset changes, and use a patch for compatible Dart-only changes.
Flutter workflow
mach ota setup --profile <profile>
mach ota verify --profile <profile>
mach ota release --platform all --profile <profile>
mach ota publish --platform all --profile <profile> --track <track> --release-version latest
mach ota promote --release-version 1.2.0+42 --patch-number 1
Expo Apps
For Expo projects, `mach ota setup` writes the `ota` block in `mach.config.json`, refreshes the project-local Mach package when it is older than the CLI, and wires `@radhya/mach/expo-plugin`. The plugin reads Mach config during Expo prebuild and sets `updates.url` and `runtimeVersion`, so updates are served from Mach, not EAS Update.
mach.config.json
{
"framework": "expo",
"ota": {
"enabled": true,
"engine": "expo-updates",
"channel": "production",
"url": "https://mach-api.securejs.in/api/ota/expo/<projectId>",
"runtimeVersionPolicy": "appVersion"
}
}
Setup offers to install the Expo-compatible `expo-updates` version. With the default `ON_LOAD` setting, the first cold launch downloads a compatible update and the next cold launch runs it. Build, verify, and publish commands stop if Expo resolves a different URL, channel, or runtime than Mach expects.
Vanilla React Native
Bare React Native uses the same open-source `expo-updates` runtime and Mach endpoint as Expo projects. Setup installs Expo Modules when they are missing, installs the compatible `expo-updates` package, and uses Expo's native configuration sync to update the committed Android and iOS projects. It does not run prebuild or replace native folders.
mach.config.json
{
"framework": "react-native",
"ota": {
"enabled": true,
"engine": "expo-updates",
"channel": "production",
"url": "https://mach-api.securejs.in/api/ota/expo/<projectId>",
"runtimeVersionPolicy": "appVersion"
}
}
Run setup from a clean branch and review the package and native changes. Then make and install one new native build. The future `mach-react-native` engine is reserved and cannot currently be used for publishing.
Dashboard Stats
The OTA dashboard shows unique downloaded, applied, and failed device counts for each update and platform. Mach derives these automatically from Expo Updates requests; no metrics code or storage credentials are added to the app. A download is visible first, and applied is confirmed when the updated app makes its next update check.
See Configuration for the `ota` field reference.