EAS Update — Over-the-Air Updates
Push JavaScript code fixes directly to your users' phones in minutes — without submitting a new build to the App Store or Play Store.
Your app has been live for two weeks. A critical bug appears: the fee payment form crashes when a parent enters a phone number with spaces. Real users are hitting this. Every minute the bug is live, potential fee payments are lost.
Without EAS Update: fix the bug → build a new production binary (10–15 minutes) → submit to the Play Store → wait 1–3 days for Google's review → wait for users to update the app → bug is fixed. Total time: 3–5 days.
With EAS Update: fix the bug → run one command → users get the fix the next time they open the app. Total time: 5 minutes.
This is what EAS Update does. It is one of the most practically valuable features of the Expo ecosystem.
The "Why First" Scenario
The EduTrack customer app has been live for a month. 500 users have downloaded it.
A user reports that the "Select Service" dropdown shows a blank list on Android 12. You investigate — it's a one-line bug in a formatting function.
If you had to go through the full Play Store submission process: the bug would be live for 2–4 days minimum. Some users would uninstall the app in frustration. The client would be upset.
With EAS Update: you fix the one line, run
eas update --branch production --message "Fix service dropdown on Android 12", and within minutes users are getting the fix silently in the background — without any app store involvement.
How EAS Update Works (Non-Technically)
Think of your app as having two layers:
Layer 1 — Native shell (compiled code): The C++ and Java/Objective-C code that runs the app's engine. This includes things like camera access, push notification handling, background location. This layer changes rarely. Changes here require a full EAS Build and store submission.
Layer 2 — JavaScript bundle (your code): Your React Native components, your business logic, your screens, your API calls, your styles. This is everything you write in TypeScript. This layer changes constantly — every bug fix, every UI adjustment, every new feature that doesn't need a new native module.
EAS Update only updates Layer 2. It sends the new JavaScript bundle to users' devices over the internet, silently, the next time they open the app. The native shell stays the same.
The Excel analogy: think of the native shell as the Excel application itself (Excel.exe), and the JavaScript bundle as the workbook you open inside it. EAS Update replaces the workbook without reinstalling Excel. Most day-to-day work happens in the workbook.
What EAS Update Can and Cannot Update
| Change | EAS Update | Requires new build + store submission |
|---|---|---|
| Bug fix in a component | Yes | No |
| UI layout changes | Yes | No |
| New screen added (no new native modules) | Yes | No |
| Text, copy, labels changed | Yes | No |
| Business logic changes | Yes | No |
| Supabase query changes | Yes | No |
| New npm package added (pure JS package) | Yes | No |
| New npm package with native code | No | Yes |
| Push notification setup changes | No | Yes |
| App icon or splash screen changed | No | Yes |
| New device permissions added | No | Yes |
| SDK version upgrade | No | Yes |
app.json changes | No | Yes |
Rule of thumb: If the change is entirely in .ts or .tsx files and doesn't add a new native module, EAS Update can deliver it. If it touches app.json, native files, or requires a new library with native code, you need a full build.
Setting Up EAS Update
Install expo-updates in your project
This installs the native module that handles receiving and applying OTA updates.
Configure EAS Update
This command:
- Adds update configuration to your
app.json - Sets up the update URL (pointing to EAS's update servers)
- Creates a
eas.jsonupdate configuration if it doesn't already have one
After running this, your app.json will have a new section:
Build a new binary that includes expo-updates
Because expo-updates is a native module, adding it requires a new build. Do this once:
Install this new build on your test device. From this point forward, this binary will check for OTA updates every time it launches.
Pushing an Update
This is the command you'll run most often after initial setup:
Breaking down the command:
| Part | What it does |
|---|---|
eas update | Start an OTA update push |
--branch production | Send the update to the "production" channel (described below) |
--message "..." | A human-readable label for this update — appears in the Expo dashboard |
EAS bundles your current JavaScript code, uploads it to EAS servers, and marks it as the latest update for the production branch.
The output:
How Users Receive Updates
EAS Update checks for updates at app launch using this logic:
- User opens the app
- The native shell (which contains
expo-updates) pings the EAS update server: "I'm on branchproduction, runtime versionsdk-52. Any updates for me?" - If yes: download the new JavaScript bundle in the background
- The next time the user fully closes and reopens the app, the new bundle runs
Important: Users do not see a prompt. Updates are silent. The update downloads in the background while they use the current version, then applies on the next full restart.
This default behaviour is intentional — it means you can fix bugs without interrupting users. If you need to force an immediate restart (for a critical fix), you can do so with additional configuration — but silent background updates are the standard approach.
Branches — Managing Multiple Release Tracks
EAS Update uses branches to let you send different updates to different groups of users.
| Branch | Who gets it | Use case |
|---|---|---|
production | All real users who downloaded the app from the store | Live bug fixes and safe feature updates |
staging | Your team and beta testers | Testing updates before they go to all users |
preview | Internal development testing | Unstable changes you want to test on a real device |
You control which branch a build is connected to via eas.json. The production APK/IPA you submitted to the store is configured to follow the production branch. Your internal test build follows the preview branch.
To push an update to staging for your team to test first:
To promote that update to production after testing:
Checking Update Status
In the Expo dashboard (expo.dev → your project → Updates tab):
| Column | What it shows |
|---|---|
| Branch | Which branch the update was pushed to |
| Runtime version | Which binary version can receive this update |
| Message | Your human-readable label |
| Created | Timestamp |
| Installs | How many devices have applied this update |
The "Installs" count is the most useful number — it tells you what percentage of your user base is on the latest version.
The Runtime Version Concept
OTA updates only work if the binary's runtime version matches the update's runtime version.
This means: an OTA update you push today will only reach users who are running the most recent binary from the store. Users still on an older binary version (who never updated the app from the store) won't receive the OTA update because the JavaScript bundle might require a native module that the older binary doesn't have.
In practice: Push OTA updates frequently for JavaScript-only changes — they reach most users immediately. But for native changes (new packages, permissions, SDK upgrades), do a full EAS Build and store submission, and let users update through the store naturally over a few days.
This is why maintaining a reasonably current app version in the stores matters — the more current the store version, the higher the OTA reach.
Rollback
If an OTA update introduces a problem, you can roll back to the previous update:
This points the production branch back to the previous update. Users who already received the bad update will get the rollback on their next app open.
Rollback is fast — it doesn't require a new build, just redirecting the branch pointer.
A Practical Update Workflow
Here's how this looks in practice during the EduTrack production phase:
Total time from bug report to fix reaching users: under an hour for a JavaScript bug.
What You Have Now
A complete picture of EAS Update: what it can update, how to push updates, how users receive them, how to manage branches, and how to roll back if something goes wrong.
Combined with EAS Build and the App Store submission knowledge, you now have the full lifecycle: build → test → submit → maintain. The verification page confirms everything is in place.