expo-updates (EAS Update) to Cresc migration guide
If your Expo app's monthly EAS Update bill is climbing with updated MAUs ($0.005/MAU) and edge bandwidth ($0.10/GiB), you can keep your Expo workflow (Expo SDK, Expo Router, expo prebuild, and even EAS Build if you want it) while switching OTA delivery to Cresc (react-native-update).
This guide maps expo-updates configuration, JavaScript APIs, hooks, runtimeVersion, and eas update CLI commands directly to their Cresc equivalents for Expo SDK 50 and later (through SDK 57). For a side-by-side cost breakdown first, see Expo pricing vs Cresc.
1. Swap expo-updates for react-native-update
Do not leave expo-updates installed alongside react-native-update — both hook into native startup bundle resolution and will conflict.
Clean app.json / app.config.ts by removing the "updates" block (url, checkAutomatically, fallbackToCacheTimeout) and "expo-updates" plugin entry if present. You can also remove "runtimeVersion" if nothing else in your tooling reads it.
Then regenerate native projects:
On Expo SDK 50+ with react-native-update >= 10.28.2, expo prebuild configures the native bundle URL on both iOS and Android automatically — you do not need to edit AppDelegate, SceneDelegate, or MainApplication by hand. (Using New Architecture? Prefer Expo SDK 51 or newer.)
Create your iOS and Android apps in Cresc so update.json is written in your project root:
2. Replace automatic update config (app.json → Cresc client)
expo-updates configured automatic check timing in app.json; Cresc configures it in JavaScript when constructing the client and wrapping your root layout (for example app/_layout.tsx in Expo Router or App.tsx):
Configuration mapping
3. Map Updates.* methods and useUpdates()
If your app builds a custom "Check for updates" screen or update banner using import * as Updates from "expo-updates", set updateStrategy: null on new Cresc(...) and use useUpdate():
Before and after: manual check & reload button
Full hook and client options are documented in the JavaScript API Reference.
4. Replace runtimeVersion with native baseline uploads
In EAS Update, runtimeVersion is a string contract ensuring JS updates only land on compatible native binaries. Cresc goes one step further: you upload each compiled store binary (.ipa, .apk, or .aab), and Cresc records both its native version (CFBundleShortVersionString / versionName) and its exact embedded Hermes bundle so every OTA version bound to it ships as a 3.4 KB–98 KB binary diff — including the first hotfix right after a store release.
Yes — you can keep using EAS Build (eas build --platform ios) if you like! Just download the finished .ipa / .aab artifact in CI (or build locally / on GitHub Actions) and pass it to cresc uploadIpa / cresc uploadAab before submitting to the stores.
5. Map eas update CLI and Expo Router entry point
index.js
Modern Expo Router projects set "main": "expo-router/entry" in package.json without a root index.js file. Create a one-line index.js at the project root so cresc bundle always resolves the entry cleanly:
CLI command mapping
In GitHub Actions, publishing to both platforms looks like:
See CLI Tools and Publishing Hot Updates for every flag.
FAQ
Can I use Cresc in an Expo app without ejecting?
Yes, with Continuous Native Generation (npx expo prebuild) or development builds (npx expo run:ios / npx expo run:android) on Expo SDK 50 and later. You keep app.json, config plugins, and Expo SDK packages. Only Expo Go is unsupported, because custom native modules cannot run inside the generic Expo Go sandbox.
Can I keep EAS Build and EAS Submit while switching OTA updates to Cresc?
Yes. Cresc only replaces expo-updates (EAS Update). Many teams continue building signed binaries on EAS Build (using the build credit included in their plan or free/CI runners), upload the resulting .ipa and .aab artifacts to Cresc as baselines, and run all OTA traffic through Cresc's flat-rate CDN tiers.
Why must I uninstall expo-updates before building?
Both expo-updates and react-native-update register native hooks to supply the JavaScript bundle URL at app launch. Leaving both installed causes startup conflicts where updates download but never activate.
How much smaller and cheaper are updates after switching from EAS Update?
Cresc's Pro plan is $99/month flat for 1,000,000 daily update checks with global CDN delivery included and zero MAU or bandwidth overage fees (compared with $449+/month at 100,000 updated MAUs on Expo Production). On payload size, Cresc's Hermes-aware diff ships a one-line fix in 3.4 KB versus 93.7 KB with plain bsdiff.