Compatibility
Everything DeployPulse does and does not work with, in one place. If you only read one table, read Your project setup.
DeployPulse speaks two OTA protocols: the CodePush protocol via
@deploypulseio/react-native-code-push, and the Expo Updates v1 protocol via expo-updates.
Most services implement one or the other. Pick whichever matches your app.
Your project setup
| Setup | Notes | Status |
|---|---|---|
| Bare React Native | iOS and Android projects | Supported |
| Expo prebuild / CNG | Config plugin runs during expo prebuild | Supported |
| EAS Build | For development and release binaries | Supported |
| Expo Go | Development sandbox, not a distribution channel | Not applicable |
Why Expo Go is "not applicable" rather than "not supported"
Expo Go is a fixed app published by Expo, so you cannot add the native module the CodePush SDK
needs. Expo disables most of the Updates API there too, and updates published with a
runtimeVersion cannot be loaded in Expo Go,
which is exactly what our manifest endpoint serves.
This is not a DeployPulse limitation. No OTA provider works in Expo Go, including Expo's own EAS
Update. Expo Go is for development; you ship to users from a development build or a release
build, and OTA updates apply there. Use expo-dev-client and the answer becomes Supported.
OTA protocol
| Protocol | How you point it at DeployPulse | Status |
|---|---|---|
@deploypulseio/react-native-code-push | CodePushServerURL / CodePushServerUrl | Supported |
expo-updates (Expo Updates v1) | updates.url in app.json | Supported |
| EAS Update | Replaced by DeployPulse, not used alongside it | Not applicable |
| Both SDKs in one binary | Pick one OTA runtime per app | Not supported |
The last row is a property of React Native, not of DeployPulse: two update runtimes both trying to own the JS bundle at launch will fight. One app, one OTA runtime. You can absolutely run a CodePush app and an Expo Updates app side by side in the same account.
For the Expo Updates path, point updates.url at your project. It is the same shape EAS uses, so only the
host and the ID change:
{
"expo": {
"updates": {
"url": "https://apps.deploypulse.io/expo/v1/YOUR_PROJECT_ID/manifest"
},
"runtimeVersion": { "policy": "appVersion" }
}
}
Your project ID is shown on the app's page in the dashboard, and printed when you create the app with dpctl. Like the project ID EAS gives you, it is public: it identifies the app and grants nothing on its own.
Channels work the way they do on EAS. Every Expo app starts with three channels, development,
preview and production, matching the profiles eas build:configure generates. A build reads the channel
named by the channel of its eas.json profile, or by an expo-channel-name entry in
updates.requestHeaders. With neither, it reads production. Channel names match case-insensitively, so an
existing eas.json keeps working unchanged:
{
"build": {
"preview": { "channel": "preview" },
"production": { "channel": "production" }
}
}
Create the app with dpctl app add MyApp --platform expo-v1. Expo Updates releases are only accepted by an
app created this way, and an app's platform can't be changed later.
Then release from your project folder:
dpctl release-expo MyApp -d production
release-expo runs npx expo export, works out each platform's runtime version from your app config
the same way expo-updates does, and uploads iOS and Android as separate releases. Add
--platform ios or --platform android to release one of them. Without -d it releases to preview,
so nothing reaches production by accident. It needs dpctl 1.2.0 or later.
If your CI exports in an earlier step, release that folder instead of exporting again:
npx expo export --output-dir dist
dpctl release-expo MyApp -d production --exportDir dist
Runtime versions are still read from the project, so run this from the project folder. If that isn't
possible, pass --runtimeVersion as well. With the fingerprint policy iOS and Android usually have
different runtime versions, so in that case release each platform separately with --platform and its
own --runtimeVersion.
To release to part of a channel first, add --rollout, then raise it with dpctl patch as confidence
grows:
dpctl release-expo MyApp -d production --rollout 10%
dpctl patch MyApp production --rollout 50%
dpctl patch MyApp production --rollout 100%
Devices are picked by their EAS client ID, so each device keeps the same answer from one launch to the
next, and a device that got the update never loses it as the percentage rises. The other devices keep
the last release that went to everyone. A rollout can only be raised, and a channel takes a new release
for a platform and runtime version only after its current rollout reaches 100%. On an Expo Updates app,
dpctl patch changes the rollout only.
If a release turns out to be bad, roll the channel back:
dpctl rollback MyApp production
That publishes the previous release again, under a new ID. Republishing is what actually moves devices:
expo-updates only loads an update newer than the one it launched, so taking the bad release out of
service on its own would leave every device that already downloaded it exactly where it was. The bad
release is disabled at the same time, which also clears any partial rollout it had, so the channel is
free to take a new release. A channel serves one release per platform and runtime version, and all of
them roll back unless you narrow it with --platform or --runtimeVersion.
When a channel has no earlier release, or every release on it is bad, send devices back to the bundle built into the store binary:
dpctl rollback MyApp production --toEmbedded
This is Expo's rollBackToEmbedded directive. Those devices stay on the embedded bundle until the
channel gets a new release, which supersedes the rollback. Releases have no labels here, so
--targetRelease is CodePush only.
See Expo Setup for the CodePush path. Code Signing covers signing CodePush releases.
React Native versions
The SDK version below is @deploypulseio/react-native-code-push.
| React Native | SDK version | Architecture |
|---|---|---|
| < 0.76 | Use react-native-code-push (Microsoft) | Old only |
| 0.76 – 0.79 | 10.0+ | Old + New |
| 0.80 | 10.1+ | Old + New |
| 0.81 | 10.3+ | Old + New |
| 0.82+ | 10.4+ | New only |
React Native 0.76 enabled the New Architecture by default, and Microsoft's original
react-native-code-push does not support it. The maintained fork supports both. See
New Architecture for what that means in practice.
iOS minimum deployment target: 15.1
Expo SDK versions
| Expo SDK | CodePush config plugin |
|---|---|
| 52+ | Supported |
| < 52 | Not supported |
The SDK 52+ floor is a requirement of the config plugin, which needs React Native 0.76+. The
expo-updates path has no Expo SDK floor of its own: it requires only that your client speaks
Expo Updates protocol version 1, which our manifest endpoint enforces.
Platforms
| Platform | Status |
|---|---|
| iOS | Supported |
| Android | Supported |
| React Native for Web, Windows, macOS | Not supported |
Still not sure?
If your setup is not on this page, get in touch and we will tell you plainly whether it works. We would rather say no early than have you find out after integrating.
