A 60MB app is not a technical detail. It is a conversion problem.
Google Play's own analysis has consistently found that install conversion drops measurably for every few megabytes of additional download size, and the effect is strongest exactly where many of us ship: mid-range Android devices, constrained data plans, patchy connectivity. If you are building for users in India, Southeast Asia, or Latin America, app size is a growth metric, not a housekeeping task.
The problem is that most guides jump straight to tips without explaining where the space actually goes. So let us start there.
What Is Actually Inside Your Android Binary
Unzip a release build and you will find the space distributed across four buckets, roughly in this order:
- Native libraries. Usually the largest single contributor. This is the React Native runtime, the JavaScript engine, and the compiled code of every native module you depend on — multiplied by every CPU architecture you ship.
- The JavaScript bundle. Your application code plus every JavaScript dependency you import, minified into one file. Smaller than people expect, typically a few megabytes.
- Assets. Images, fonts, videos, Lottie animations. This is where projects quietly balloon over time, because nobody notices one more PNG.
- Resources and manifests. Android XML resources, string translations, density-specific drawables.
The critical insight is the multiplication in that first bucket. If you ship a universal APK supporting four CPU architectures, every native library appears four times. Your React Native runtime, your image library, your analytics SDK, your payments SDK — all of it, four times over, and each device uses exactly one copy.
Fix 1: Ship an App Bundle, Not a Universal APK
This is the highest-return change available and it requires no code modifications at all.
An Android App Bundle hands Google Play the components of your app rather than a finished package. Play then generates a minimal APK per device: one CPU architecture, one screen density, the languages that device uses. The user downloads a fraction of what a universal APK would have forced on them.
Typical reduction is 30 to 50 percent. If you are still publishing a universal APK in 2026, this is where to start, and you can do it this afternoon.
If you distribute outside Play — enterprise deployment, direct download, alternative stores — use ABI splits to generate separate APKs per architecture and serve the right one. Same principle, more manual.
Fix 2: Confirm Hermes Is Actually On
Hermes is a JavaScript engine built specifically for React Native. Instead of shipping source that gets parsed and compiled at startup, it ships bytecode compiled ahead of time during your build.
Two benefits follow. The engine binary is smaller than JavaScriptCore, and your JavaScript ships as compact bytecode rather than text. Startup time improves as a side effect, often noticeably on low-end hardware.
Hermes is the default in current React Native versions, but plenty of production apps were started before that and never migrated. Check your build configuration rather than assuming. On an older project this is frequently the single biggest win available after the App Bundle change.
Fix 3: Turn On Minification and Resource Shrinking
R8 — the Android toolchain's optimiser and shrinker — removes unused classes and methods from your native dependencies and shortens names. Resource shrinking removes drawables, layouts and strings that nothing references.
Both are disabled by default in many React Native templates, which surprises people. Enabling them is a build configuration change.
The caveat: aggressive shrinking can remove code that is only referenced reflectively, which is common in native SDKs. Some libraries ship their own keep rules and some do not. Enable it, then test the full app carefully — particularly payments, analytics, push notifications and anything using reflection. Do not enable it the day before a release.
Fix 4: Audit Native Modules Ruthlessly
Not all dependencies cost the same. A JavaScript-only package contributes roughly the size of the code you import from it. A native module contributes compiled libraries for every architecture, plus its own transitive native dependencies.
So the audit that matters is not "how many packages do we have" but "how many native modules do we have, and does each earn its place."
Things I would look at specifically:
- Analytics and crash SDKs. Teams frequently ship two or three overlapping ones because each was added for a different reason and nobody removed the previous.
- Full SDKs used for one feature. A complete maps SDK for a single static location view, or a full video framework for one short clip.
- Abandoned experiments. The package added for a feature that shipped, got reverted, and left its native dependency behind.
- Icon libraries. Bundling every icon font when the app uses fifteen icons.
Fix 5: Take Assets Seriously
Assets are where apps grow without anyone deciding to grow them. A designer exports at 3x, someone drops it into the repo, and the app is 400KB heavier forever.
Practical measures:
- Use WebP instead of PNG. Typically 25 to 35 percent smaller at equivalent visual quality, supported everywhere you care about.
- Subset your fonts. A full font family includes glyphs for scripts your app will never render. Subsetting to the characters you actually use routinely cuts font weight by 80 percent or more.
- Never bundle video. Stream it or download on first use. A single short clip can outweigh your entire JavaScript bundle.
- Load large animations remotely. Lottie files are JSON and can be surprisingly large. Fetch and cache them rather than shipping them.
A Realistic Order of Operations
If you want the shortest path from bloated to lean:
- Switch to an Android App Bundle. No code changes, largest single reduction.
- Verify Hermes is enabled. Configuration change, helps size and startup together.
- Enable R8 and resource shrinking. Configuration change, then test thoroughly.
- Audit native modules and remove what does not earn its place. This is the slowest step and often the most valuable.
- Convert images to WebP and subset fonts. Mechanical, safe, cumulative.
- Measure the actual download size from the Play Console, not your local build output.
That last point deserves emphasis. The file size on your machine is not what users download. Play Console reports the real per-device download size after Play has generated the tailored APK. Optimise against that number, because it is the one your install conversion responds to.
Why This Is Worth Your Time
App size work is unglamorous. It ships no features and demos poorly. But it is one of the few engineering tasks that directly moves a business metric you can point at, and the effect applies to every future install rather than decaying like a marketing campaign.
If you are shipping to price-sensitive or bandwidth-constrained markets, it may be the highest-leverage week of engineering available to you.
Building or maintaining a React Native app and want an audit? See how I work on mobile or get in touch.

