How to keep your OTA updates lean and fast
Product•Development•React Native••12 minutes read
Jacob Clausen
Engineering
Ship faster OTA updates to your React Native users with smaller bundles, smarter rollouts, and practical techniques to optimize your OTA Update usage.

Have you ever shipped a critical fix to your entire user base within minutes of merging the PR - a straight highway from your fix to your users’ fingertips, no bureaucracy, no interruption to the user experience? That feeling never gets old.
EAS Update makes this possible, and once you’ve experienced it, it’s hard to imagine working without it. But publishing the fix is only half the story. Your users don’t benefit until it’s running on their devices. The faster that download completes, the sooner your fix is in their hands. And the leaner your updates are, the better the experience gets for everyone. Faster downloads, lower costs, and a smoother ride as your team and user base grow. In this guide, we’ll walk through how to keep your updates small, ship them with confidence, and get the most out of every push.
EAS Update pricing recap
To get the most out of EAS Update, it helps to understand two concepts that shape how your updates are delivered and billed: Monthly Active Users (MAUs) and bandwidth. Knowing how they work, and the things you can do to keep your updates lean, means faster downloads for your users and lower costs for you. This blog post assumes you’re already familiar with what EAS Update is and what scenarios it’s useful for.
Monthly Active Users (MAUs)
A Monthly Active User (MAU) is a unique user who downloads at least one update via EAS Update within a single billing period. No matter how many updates they download that month, they still count as one MAU. And if a user checks for updates but nothing new is available (so no download happens), they’re not counted at all.
Uninstalling and reinstalling the app will count as a separate MAU the next time they download an update. Similarly, the same person on two different devices would count as two MAUs. These edge cases probably won’t dramatically change your numbers, but they’re good to be aware of if your actual MAU count doesn't exactly match Play and App Store counts or metrics that consider more context about the unique identities of your users.
Bandwidth
While every update a user downloads consumes bandwidth, the quotas on each plan are generous, and most teams stay comfortably within their plan's allocation. Actual bandwidth usage tends to be much lower than you might expect, thanks to factors like compression.
The size of that download depends on what changed. For example, if only your JavaScript was updated, that’s all the user downloads. Assets already on the device from the original build (or from a previous update) aren’t re-downloaded.
That number is often smaller than you’d think: if you publish three updates in a week and a user only opens your app once that week, they download one update - not three. Only the latest update is downloaded, and the rest are skipped. From both a speed and bandwidth perspective, this is great - your users aren’t downloading more than they need to, which means updates are delivered faster and you’re only paying for what’s actually being used.
That said, keeping your updates lean is still worth doing for a bunch of reasons beyond billing: faster downloads, less data usage for your users, and a snappier experience all around. More about this later.
One thing we’re really excited about: with SDK 55, you can opt in to Hermes bytecode diffing (currently in beta, please check it out!). Instead of downloading a full JavaScript bundle, the client applies a binary diff to what’s already installed. This can reduce download sizes significantly, meaning your users get updates faster and you can ship more frequently. It’s one of the ways we’re actively working to make updates both cheaper to deliver and better for your users.
Why smaller updates matter
The smaller your updates are, the faster they download for your users - and the less bandwidth each update consumes, both for your EAS Update usage and for your users on cellular or limited data plans. Smaller bundles also mean faster builds, and when your app loads an update on launch, a leaner bundle means a snappier startup. And if your bundle gets large enough, you might even notice it during development - live reload can start to feel slow when it has to process a big bundle on every change. Here are some techniques worth knowing about.
Optimize your assets
Images can add up quickly in your update size, so it’s worth making sure they're optimized before you ship. Compressing your images where possible can make a meaningful difference - often with little to no visible quality loss. The smaller your images, the faster your updates download and the less data your users consume.
Let your assets be assets
When an image is a proper asset file, it gets downloaded once (either through a build or an update) and stays on the device. Future updates skip it entirely if it hasn’t changed. But when assets are inlined in your JavaScript (like for example base64-encoded images), they’re part of the bundle itself, so they come along for the ride on every update.
For images that change frequently or live outside your bundle entirely, serving them from a CDN paired with expo-image is worth considering. Its default caching policy persists images to disk on first load, so they behave just like bundled assets after that (downloaded once, reused across app restarts) without adding any weight to your updates.
Choose which assets go into your updates
Not every asset in your project needs to be delivered through updates. With asset selection, you can specify exactly which assets should be included using file patterns in your app config. Everything else stays in the native build and never gets downloaded from the update server.
For example, if only the images in your app/images directory change between releases, you can limit your updates to just those:
{"expo": {"updates": {"assetPatternsToBeBundled": ["app/images/**/*.png"]}}}
Once you’ve configured your patterns, run npx expo-updates assets:verify before publishing. This ensures that all required assets will be included when you publish an update - assets that fall through the cracks won't be available, which can cause unexpected behavior or crashes. Check out the docs for more details.
Submit to the app stores regularly
When you submit a new build to the app stores, it includes all your latest assets. That means any OTA updates you publish after that only need to include what’s changed since the build, so users download less. If you’ve recently added large or multiple new assets, shipping a new build is a good way to keep your next updates lean.
One approach that works well is pairing a regular binary release cadence (say, monthly) with OTA updates for changes in between. Your users get improvements more frequently, and each new binary resets the asset baseline for your subsequent updates.
Keep your JavaScript bundle in check
Your JavaScript bundle is part of every update you publish. Tools like Expo Atlas give you a visual breakdown of your bundle, showing exactly how much space each dependency takes up. It can be a real eye-opener - you might discover a library you imported for a single utility function is pulling in way more than you expected, or spot a dependency you stopped using but never removed.
You can try it right now with your local dev server. Start your app with Atlas enabled:
EXPO_ATLAS=true npx expo start
Then press shift + m in the terminal running the dev server to open the dev tools plugin menu and launch Atlas.
Shipping updates efficiently
So far we’ve covered how to keep your updates lean. But the way you ship updates matters too. Rollouts give you more control over how updates reach your users, and using updates for internal testing can save you time and build credits.
Use rollouts for production updates
When you publish an update, it’s available to your entire user base by default. Every update your users download counts toward your bandwidth usage, so rollouts are a natural way to be efficient: start with a small group, make sure everything looks good, and then roll it out to everyone.
Use updates for internal testing and PR previews
During development, getting changes in front of your team for review often means creating a new build. But for changes that don’t involve native code, an OTA update does the same job - and it takes only seconds. Your team can preview changes directly on a development build they already have installed, or even from a pull request preview that’s generated automatically.
The more of your review and iteration cycle that happens through updates rather than builds, the less time you spend waiting around before anyone can look at a change. Your team can have the latest version on their device in seconds, which means the feedback loop opens up much earlier in the process. That adds up fast when you’re iterating on a feature, and you’re saving build credits along the way. And since it’s just your team downloading these updates, the MAU and bandwidth cost is practically zero, making it one of the best value-for-effort wins on your plan.
Keeping track of your usage
Everything we’ve covered so far (keeping updates lean, using rollouts, leveraging updates for internal testing) all contributes to getting more value out of your EAS Update plan. But it’s also nice to know where you can see how things are going.
Monitor your usage in the dashboard
Expo provides a usage overview on your account’s Billing and Usage pages. There you’ll find a summary of your EAS Update usage: how many MAUs have downloaded updates and how much bandwidth has been consumed during the current billing cycle (or given time period). It’s a handy way to stay informed, especially if you’re curious how your numbers look after a big release.
Use the pricing calculator to find the right plan
If you’re trying to figure out which subscription plan fits your needs, the pricing calculator on the Expo website can help. Adjust the sliders for your expected MAU count, builds, and CI/CD minutes, and it’ll recommend a plan - and if your numbers go beyond what’s included in that plan, it’ll show you the estimated cost of that extra usage too.
Pick the plan that fits today
You don’t need to have everything figured out before choosing a plan. Start with what fits your current needs - you won’t hit a wall if your app grows faster than expected. Every plan scales naturally with your usage, and you can move between plans as your needs change. Expo’s pricing is designed to grow with you, not get in the way. EAS Update is available on every plan, including the free plan, so you can try it out without any commitment.
Wrap-up
At the end of the day, EAS Update gives you a pretty sweet deal: ship updates to your users in seconds, iterate faster with your team, and scale at your own pace. Leaner updates, rollouts, and a few of the techniques we covered are all it takes to deliver a faster experience for your users while getting more value out of your plan.
Ready to get started? Set up EAS Update in your project - it only takes a few minutes to set up, and you can start shipping updates right away. If you want to dive deeper into any of the topics we covered, the EAS Update docs are a great next step. We’d love to hear about your success story with EAS Update too!




