Yes. Over-the-air (OTA) updates in Expo do not depend on EAS Update. expo-updates is a library that fetches bundles from any server speaking the Expo Updates protocol, and EAS Update, now called Expo Update in Expo's documentation, is one such server. You have three realistic options in 2026: self-host a server for expo-updates, replace expo-updates with a third-party SDK, or stay with Expo Update. None of the three works in Expo Go.

This post explains each option with the exact configuration, what you take on, what it costs, and a decision rule at the end. Facts and prices were retrieved on 2026-11-07.

Why does Expo Go not receive custom OTA updates?

Expo Go is a prebuilt app from the stores. Expo's own FAQ says it "comes with a fixed set of native libraries built in" and that "there is no way to get the native code into the Expo Go app unless it was already included in the bundle". Expo describes it as "a playground app, so it's limited and not useful for building production-grade projects".

An OTA update needs a native update client inside the binary, configured with your server URL or your SDK. Expo Go carries Expo's own configuration and nothing else. So every option below requires a build of your own app. Expo calls that a development build when it includes expo-dev-client, and a release build otherwise. A development build is "essentially your own version of Expo Go where you are free to use any native libraries".

One more thing applies to all three options: by default a debug build loads its JavaScript from the development server and applies no published update. A development build with expo-dev-client can open an Expo Update from its launcher screen for testing, but that is a testing path, not the one your users take. Test OTA updates with a release build:

npx expo run:android --variant release npx expo run:ios --configuration Release 

Option 1: Self-host a server for expo-updates

Expo's SDK documentation states that expo-updates can be configured manually for "cases where a different remote update service is required" and that "it is also possible to use this library with a custom server". Expo publishes a reference implementation at expo/custom-expo-updates-server.

Your server must implement the Expo Updates protocol, version 1. The spec names its audience as "Expo Services and organizations that wish to manage their own update server to satisfy internal requirements". The client sends three headers on every request, expo-protocol-version, expo-platform and expo-runtime-version, and your server answers with a manifest and the assets.

The app configuration points expo-updates at your server:

{ "expo": { "runtimeVersion": { "policy": "fingerprint" }, "updates": { "url": "https://updates.example.com/api/manifest", "codeSigningCertificate": "./certs/certificate.pem", "codeSigningMetadata": { "keyid": "main", "alg": "rsa-v1_5-sha256" } } } } 

runtimeVersion is required. It is Expo's compatibility rule: a build and an update are paired only when their runtime versions match. The fingerprint policy computes it from a hash of your dependencies, native code, native project files and configuration. The appVersion and nativeVersion policies tie it to version numbers you bump by hand.

What you own with this option:

  • Hosting and a CDN for manifests and assets, with the uptime your users expect.
  • Building the update with npx expo export, uploading it, and writing the manifest.
  • Runtime version bookkeeping, so an update for a new native layer never reaches an old build.
  • Code signing keys, if you set codeSigningCertificate. Expo verifies signatures on the client before an update is applied.
  • Rollbacks, staged rollouts and per-device targeting, none of which the protocol provides for you.
  • Hermes compatibility. Expo's Hermes guide notes that "an update produced for a specific version of Hermes will not run on a different version of Hermes", so an SDK upgrade must move the runtime version.

This option fits teams with an internal requirement, such as data residency or an air-gapped network, and the infrastructure skills to run a small service. The cost is your time and your servers, not a monthly bill.

Option 2: Replace expo-updates with a third-party SDK

The second option swaps the update client. A third-party SDK brings its own native module and a config plugin that wires it into the native projects at npx expo prebuild. Because two update clients cannot both decide which bundle the app runs, expo-updates has to go, or updates.enabled has to be false.

HotCodePush, the OTA update service for React Native, Expo, Capacitor and Cordova, is one of these SDKs. Its Expo package is a config plugin over the React Native module, and the setup is one command:

npx hotcodepush init 

That installs @hotcodepush/expo-ota-updates, adds the plugin to app.json and writes a hotcodepush.json with the app id and the channel:

{ "expo": { "plugins": ["@hotcodepush/expo-ota-updates"] } } 

Run npx expo prebuild, build a release, then publish:

npx hotcodepush release create 

The CLI bundles each platform with npx expo export:embed and Hermes, as the store build does, uploads the bundles and creates the release. There is no runtime version to type. Compatibility comes from a fingerprint of the native dependencies in your lockfile, stamped into every build and computed for every bundle at upload. A device whose binary carries another fingerprint skips the release and keeps running what it has.

Facts about the HotCodePush option:

  • Supports Expo SDK 55 to 58. The prebuild refuses a project that still has expo-updates enabled and tells you to disable it.
  • A store build, an Xcode archive, EAS Build or a release Gradle variant, registers itself with HotCodePush and needs a HOTCODEPUSH_TOKEN in that build.
  • Free for 1,000 monthly active devices, then $1 per 1,000 with a spending cap you set. Every feature is on every plan.
  • Code signing, staged rollouts with automatic pause, rollbacks and channels are part of the service.

Other SDKs in this category work on the same principle. Whichever you pick, check three things: that it supports your Expo SDK version, how it decides compatibility between a build and an update, and how it handles a debug build. The HotCodePush Expo guide is the reference for this one.

Option 3: Stay with Expo Update

Expo Update is the hosted service for expo-updates, and for many teams it is the right answer. If you build with EAS Build and want no setup at all, eas update:configure wires everything, and the runtime version policies described in option 1 apply unchanged.

Pricing on expo.dev, retrieved 2026-11-07:

Plan Monthly price Monthly active users included Bandwidth included
Free $0 1,000 100 GiB
Starter $19 plus usage 3,000 100 GiB
Production $199 plus usage 50,000 1 TiB
Enterprise custom priced from the first user 40 TiB

On the Free plan there is no overage. Starter charges $0.005 per user from 3,001 to 200,000 users, with lower tiers above that. Production includes 50,000 users and uses the same tiers above its allowance. Both charge $0.10 per GiB over the included bandwidth.

How do the three options compare?

Self-hosted expo-updates Third-party SDK (HotCodePush as the example) Expo Update
Update client expo-updates the SDK's own module expo-updates
Server yours the vendor's Expo's
Compatibility rule runtimeVersion, you choose the policy fingerprint computed at upload runtimeVersion, you choose the policy
Code signing your certificate, optional RSA key pair from the CLI, optional Expo's, optional
Staged rollouts and rollbacks you build them included included
Works in Expo Go no no no
Applies in a debug build no by default no no by default
Works with EAS Build yes yes yes
Monthly cost at 2,000 active users your infrastructure $1 $19 on Starter
Monthly cost at 10,000 active users your infrastructure $9 $19 plus $35 usage on Starter

The last two rows are arithmetic on the public prices and will go stale. Check both pricing pages before you decide.

Which option should you choose?

  • Choose self-hosting when a policy forces the update server inside your own network, and you have someone to run it. Budget for rollouts and rollbacks, which you will want within the first month.
  • Choose a third-party SDK when you build natively yourself, with EAS Build, Fastlane, Codemagic or a plain CI runner, and want rollouts, signing and compatibility handled without maintaining a server.
  • Choose Expo Update when your whole pipeline is EAS and you want the shortest path from expo export to a device.

Whatever you pick, test it with a release build, never in Expo Go or a debug build, and make sure the compatibility rule moves whenever your native layer does. That rule, not the server, is what keeps an update from crashing a build it was never meant for.

If you try the HotCodePush route, the Expo installation page has the manual steps, and questions are welcome in the comments.