Fix 'Your app is affected by Google Play's 16 KB page size requirement' in React Native
In short
Google Play's 16 KB page size requirement rejects AABs whose 64-bit native .so libraries are not aligned to a 16 KB boundary, enforced for new submissions and updates after 31 May 2026. Find the offending libs with check_elf_alignment.sh, bump your NDK to r28+ and AGP to 8.5.1+ to fix code you build from source, and upgrade or replace any prebuilt dependency you cannot re-link. Need a hand untangling a stuck native build? See my mobile development work.

On this page
- What does the Google Play 16 KB page size warning actually mean?
- How do I find which .so files are not 16 KB aligned?
- Which React Native native libraries are the usual offenders?
- How do I bump the NDK and AGP to align my own native code?
- What if the unaligned .so comes from a dependency I cannot rebuild?
- How do I confirm the build is actually compliant before I upload?
If Google Play just told you "Your app is affected by Google Play's 16 KB page size requirement," it means one or more of the native .so libraries inside your AAB are not aligned to a 16 KB boundary, and Play will start blocking those builds for new submissions and updates after 31 May 2026. The fix is almost always the same three moves: find which .so files are misaligned with check_elf_alignment.sh, upgrade your Android NDK and Android Gradle Plugin so the linker pads segments to 16 KB, and rebuild your offending native dependencies. This post walks the diagnosis end to end so you stop guessing and ship a compliant build.
I have done this on a few React Native and Expo apps now, and the pattern is consistent enough that I can usually tell you which dependency is the culprit before I even unzip the AAB. Let me show you how to confirm it yourself.
What does the Google Play 16 KB page size warning actually mean?
It means Android is moving from 4 KB memory pages to 16 KB pages on newer 64-bit devices, and your shared libraries have to be laid out so they load correctly on both. Apps that ship arm64-v8a or x86_64 native code need every ELF segment aligned to 16 KB, otherwise the loader can fail on 16 KB devices.
The short version: this is purely a 64-bit problem. Your 32-bit armeabi-v7a libraries are irrelevant here because those devices never run 16 KB pages. The warning fires when Play inspects the lib/arm64-v8a/ and lib/x86_64/ folders inside your AAB and finds a .so whose LOAD segments are not aligned to 0x4000 (16384 bytes).
Two things are being checked, and people conflate them:
- ELF segment alignment, the
p_alignvalue ofLOADsegments, which must be at least 16384. - The uncompressed
.sobeing page-aligned and stored uncompressed inside the APK/AAB ZIP, which AGP handles for you withuseLegacyPackaging false.
The first one is where prebuilt native dependencies bite you. The second one is mostly a build-system setting. You can be compliant on one and not the other, so check both.
How do I find which .so files are not 16 KB aligned?
Use Google's check_elf_alignment.sh script against your built AAB or APK. It unzips the archive, runs objdump or llvm-readelf over every .so, and prints ALIGNED or UNALIGNED per file so you know exactly which dependency to chase.
First build a release AAB so you are testing the real artifact, not a debug build:
cd android
./gradlew bundleRelease
## output: android/app/build/outputs/bundle/release/app-release.aab
Then grab the script from the Android platform tools and run it:
## Fetch the official script
curl -O https://raw.githubusercontent.com/android/ndk-samples/main/16KbPageSizes/check_elf_alignment.sh
chmod +x check_elf_alignment.sh
## Run it against your AAB
./check_elf_alignment.sh app/build/outputs/bundle/release/app-release.aab
You will get output that looks roughly like this:
=== ELF alignment ===
lib/arm64-v8a/libreactnative.so: 16384 ALIGNED
lib/arm64-v8a/libhermes.so: 16384 ALIGNED
lib/arm64-v8a/libimagepipeline.so: 4096 UNALIGNED (load segment)
lib/arm64-v8a/librnscreens.so: 16384 ALIGNED
lib/arm64-v8a/libsqlite3x.so: 4096 UNALIGNED (load segment)
Found 2 unaligned libs (only arm64-v8a/x86_64 matters).
The two UNALIGNED lines are your entire problem. Note which dependency each .so belongs to. libimagepipeline.so is Fresco, used by older image stacks; libsqlite3x.so would point at a SQLite-based storage library. That mapping is the real diagnostic work, and the next section covers the usual offenders.
If you do not want to fetch the script, you can spot-check a single file by hand:
unzip -o app-release.aab -d /tmp/aab
llvm-readelf -l /tmp/aab/base/lib/arm64-v8a/libsqlite3x.so | grep LOAD
## Look at the Align column. 0x4000 is good. 0x1000 means 4 KB, unaligned.
0x4000 is 16 KB and passes. 0x1000 is 4 KB and fails.
Which React Native native libraries are the usual offenders?
In my experience the misaligned .so files almost never come from React Native core anymore. React Native itself, Hermes, and most of the heavily maintained community modules became 16 KB aligned well before enforcement. The libraries that get apps rejected are older or thinly maintained ones that ship prebuilt binaries compiled with an old NDK.
Here is the cheat sheet I work from when triaging an unaligned AAB.
| Native lib in the AAB | Comes from | Typical fix |
libreactnative.so, libhermes.so | React Native core | Bump to RN 0.77+ (aligned by default) |
libimagepipeline.so | Fresco / older image loaders | Update RN, or replace with a maintained image lib |
libsqlite3x.so, libwcdb.so | Older SQLite storage modules | Update to a current release built with NDK r28 |
libjsi.so from a stale module | Outdated JSI-based packages | Bump the package; rebuild from source |
librealm.so | Realm versions before the fix | Upgrade Realm to a 16 KB compliant release |
Map/SDK .so files | Third-party closed SDKs | Wait for vendor update or pin to their fixed version |
| Check | Command / location | Pass condition |
| ELF alignment | check_elf_alignment.sh app-release.aab | All arm64/x86_64 libs ALIGNED |
| NDK version | android/build.gradle ndkVersion | r28+ |
| AGP version | build.gradle classpath | 8.5.1+ |
| Native packaging | useLegacyPackaging | false |
| Runtime sanity | 16 KB emulator install | App launches, native screens work |
When all five pass, upload the AAB. The Play Console warning clears once it scans a compliant build, and you are set ahead of the 31 May 2026 enforcement.
One honest caveat: the static script and Play's scanner can disagree at the margins, usually because of how a specific .so declares its segments. If the script says aligned and Play still complains, the 16 KB emulator test plus a careful read of llvm-readelf -l on each library is how I have always found the straggler.
If you are staring at this rejection on a shipping app and the offending library turns out to be something abandoned in your dependency tree, that is exactly the kind of stuck native build I untangle for clients. Reach out through my contact page ↗ and send me the check_elf_alignment.sh output; that one paste tells me most of what I need to scope the fix.
FAQ
What does the Google Play 16 KB page size requirement error mean for React Native?
It means one or more 64-bit native .so libraries in your AAB are not aligned to a 16 KB boundary, which Play blocks for new submissions and updates after 31 May 2026.
How do I find which .so files are not 16 KB aligned?
Run Google's check_elf_alignment.sh script against your release AAB, and it prints ALIGNED or UNALIGNED for every native library so you know exactly which dependency to fix.
Which NDK and AGP versions fix the 16 KB alignment issue?
NDK r28 or newer makes 16 KB the default linker alignment for 64-bit targets, and pairing it with Android Gradle Plugin 8.5.1 or newer aligns any native code you compile from source.
What if the unaligned library comes from a dependency I cannot rebuild?
You cannot re-link a prebuilt third-party .so locally, so you must upgrade the dependency to a 16 KB compliant release, patch it if it builds from source, or replace it.
Do I need to worry about 32-bit armeabi-v7a libraries?
No, the 16 KB page size requirement only affects 64-bit arm64-v8a and x86_64 libraries because 32-bit devices never run 16 KB memory pages.
Working on something like this?
I build web apps, AI features, and mobile products for clients. If this article matches a problem you have, tell me about it.
Start a conversationMalik Hamza Shabbir · Full-Stack & AI Engineer
I build full-stack and AI products solo: a reputation SaaS in production, RAG pipelines, and React Native apps. I write from what I ship, not from documentation summaries.
Related articles
Your React Native App Will Break on Google Play August 31, 2026: The Target API 36 Migration Checklist
Google Play makes target API 36 (Android 16) mandatory on August 31, 2026. The version bump is easy. The forced edge-to-edge display and predictive back changes that silently break your React Native layouts are not. Here is the triage checklist and EAS verification routine I run before the cutoff.
The Bridge Is Gone: Migrating a Legacy React Native App to 0.85 When New Architecture Is the Only Option
React Native 0.85 fully removed the bridge on 7 April 2026, so the New Architecture is the only option. Here is how I audit dependencies against the Directory, which libraries still crash, and the realistic effort to rescue a 0.7x Paper app.
On-Device or API? Shipping Structured Extraction With Apple 3rd-Gen Foundation Models vs a Cloud LLM
Apple's 3rd-gen on-device Foundation Models let mobile teams run classification, routing, and structured extraction for free, on-device, and offline. Here is the decision framework I use to choose on-device vs a cloud LLM, where on-device tops out, and the hybrid fallback pattern that sends only the hard cases to a paid API.