DeployPulse

Compatibility

Everything DeployPulse does and does not work with, in one place. If you only read one table, read Your project setup.

Your project setup

SetupNotesStatus
Bare React NativeiOS and Android projectsSupported
Expo prebuild / CNGConfig plugin runs during expo prebuildSupported
EAS BuildFor development and release binariesSupported
Expo GoDevelopment sandbox, not a distribution channelNot 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

ProtocolHow you point it at DeployPulseStatus
@deploypulseio/react-native-code-pushCodePushServerURL / CodePushServerUrlSupported
expo-updates (Expo Updates v1)updates.url in app.jsonSupported
EAS UpdateReplaced by DeployPulse, not used alongside itNot applicable
Both SDKs in one binaryPick one OTA runtime per appNot 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 NativeSDK versionArchitecture
< 0.76Use react-native-code-push (Microsoft)Old only
0.76 – 0.7910.0+Old + New
0.8010.1+Old + New
0.8110.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 SDKCodePush config plugin
52+Supported
< 52Not 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

PlatformStatus
iOSSupported
AndroidSupported
React Native for Web, Windows, macOSNot 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.