An Android App Bundle (AAB) is the publishing format Google Play has required for new apps since August 2021 — and it is the reason two people can install the same app and end up with very different download sizes. You no longer hand Google Play a finished APK. You hand it a bundle that carries all of your compiled code and resources plus the instructions for assembling them, and Google Play generates the split APKs that are actually installed on each device.

That one change moves a lot of decisions out of your build script and into Play: which CPU architecture receives which native libraries, which screen density receives which drawables, which locale receives which strings. It also introduces a set of hard size limits — and the limits moved. The base module ceiling is no longer 200 MB. Teams still planning around the old numbers either over-engineer their delivery strategy or lose an upload to a size error that looks inexplicable.

This guide covers the 2026 picture in the order you meet it: what the bundle contains, the current size limits, how split APKs are assembled, Play Feature Delivery and Play Asset Delivery, the version-code rules for generated APKs, testing with bundletool, and the checklist to run before you upload.


1. What an app bundle actually contains

An app bundle is the .aab artifact you upload instead of an APK. Google's own wording is precise: it includes all of your app's compiled code and resources, and defers APK generation and signing to Google Play. Inside it you will find:

The bundle itself is never installed on a device. It is a distribution source, not a package.

2. What "split" means for the user

When a user taps Install, Play builds a set of APKs for that specific device configuration, signs them, and serves them. The classic splits are:

So "download size" in Play Console is not one number, it is a range across configurations, and the App size page reports both the reference-device figure and that range. Judging a release by a single APK you built locally is how teams end up surprised by install conversion.

3. The 2026 size limits

These come from Play Console Help and are the numbers to plan around. Note how far the base module ceiling has moved from the 200 MB figure that still circulates in older guides.

Four further constraints travel with those numbers:

One legacy trap: apps still delivered as plain APKs are not covered by any of the limits above. They remain on the legacy APK rules, where the ceiling is a 100 MB APK. If an upload rejects with a size error that looks like a message from 2019, check whether the artifact you uploaded is genuinely a bundle.

4. Which mechanism do you need?

Three mechanisms solve three different problems, and mixing them up costs weeks.

5. Play Feature Delivery: install-time, on-demand, conditional

A feature module declares one of three delivery modes in its manifest:

  1. install-time — the module is part of the initial install. Users cannot skip it, and it counts toward the size the user sees.
  2. on-demand — the module is not installed until the app requests it. Your code must handle the pending, downloading, completed and failed states.
  3. conditional — the module is installed at install time only where the device meets a condition you declare, such as device features, user country, or minimum SDK version.

Conditional delivery is the one teams underuse. A tablet-only feature module, or one that only makes sense where a particular payment provider operates, does not need to sit on every device.

6. Play Asset Delivery: install-time, fast-follow, on-demand

Asset packs also support texture-compression targeting, which lets Play deliver the compression format a device's GPU actually supports instead of bundling every format. For games this is usually the single largest size win available.

7. Version codes when Play generates the APKs

With bundles you stop managing version codes per APK. You set one version code in the base module, and after upload Google Play assigns that same version code to every APK it generates from that bundle. All split APKs for one install share the version code.

The consequence is discipline, not complexity: to ship an update you increment the base module's version code and build a new, full bundle. When the user updates, Play serves updated versions of every APK currently installed on that device. Two practical rules follow:

8. Signing: the upload key, not the app signing key

With Play App Signing, the artifact you upload is signed with an upload key, and Play re-signs the generated APKs with the app signing key. The signing configuration belongs in the base module only. Two things routinely catch people out:

9. Testing split APKs before release with bundletool

The Android Gradle plugin builds the bundle; bundletool is what you use to turn it back into device-specific APKs and to emulate Play's distribution locally. Play itself uses the same tool to generate APKs, so local behaviour tracks production closely.

# Build an APK set covering every supported device configuration
bundletool build-apks \
  --bundle=app-release.aab \
  --output=app.apks \
  --ks=upload-key.jks --ks-key-alias=upload

# Deploy only the splits that match the connected device
bundletool install-apks --apks=app.apks

# Produce a universal APK for a quick sanity check
bundletool build-apks --bundle=app-release.aab --output=app.apks --mode=universal

# Enable local testing of on-demand modules and asset packs
bundletool build-apks --bundle=app-release.aab --output=app.apks --local-testing

The --local-testing flag writes metadata into the APK manifests that tells the Play Core libraries to use the local splits instead of contacting Play. Without it, on-demand download code cannot be exercised outside the store. For a device-specific spec, use bundletool get-device-spec.

Before a production rollout, the internal testing track is still the cheapest way to confirm that real installs resolve the right splits — including on the low-end devices your crash analytics care about.

10. Read the App size page before you optimise anything

Once an app has a production release, Play Console reports download size under Monitor and improve, then Android vitals, then App size. It shows the app's download size on a reference device and the range across configurations, a peer comparison for a group you define, the trend over time, and two metrics worth more than the size number itself:

11. Pre-upload checklist

  1. The artifact is an .aab, not a universal APK.
  2. The base module version code is incremented in exactly one place.
  3. The upload key is configured in the base module only, and the keystore is backed up somewhere that is not one laptop.
  4. The base module compressed download size is within 500 MB — and under 200 MB if you want to avoid the mobile-data warning on install.
  5. Each feature module is under 500 MB, and all modules plus install-time packs are under the 4 GB cumulative limit.
  6. Each asset pack is under 1.5 GB, and on-demand plus fast-follow packs stay under 30 GB.
  7. No more than 100 asset packs, and within the 100 or 50 feature-module guidance for your minimum SDK.
  8. Minimum SDK is API 21 or higher if the app exceeds 1 GB.
  9. On-demand features are implemented through the Play Core libraries, with the pending, downloading and failed states handled explicitly.
  10. Texture-compression targeting is enabled for asset packs where more than one GPU format is in play.
  11. The bundle has been tested with bundletool install-apks on at least one low-end and one arm64 device, plus --local-testing for every on-demand path.
  12. The App size page is reviewed after the release goes live, including the less-than-2-GB-free metrics.
  13. The data safety form and content declarations still match what the new modules actually collect.
  14. The store listing text and screenshots still describe the app the user now downloads, not the universal build you tested with.

12. Failures that only appear after release

  1. An on-demand module never downloads because the Play Core integration assumes success and has no retry path for a failed or cancelled request.
  2. An install-time asset pack balloons the listing size after a content drop, and install conversion falls with no code change at all.
  3. Conditional modules install on devices that do not meet the condition because it was declared in the wrong manifest.
  4. Version-code collisions when CI stamps the bundle while a legacy per-ABI scheme is still active in the build files.
  5. A wrong-key signature after a keystore rotation that was never mirrored into the base module configuration.
  6. First-run failures on slow connections when the app's first screen depends on a fast-follow pack that has not arrived yet.
  7. A data safety mismatch after a new SDK lands inside a newly split module that nobody re-declared.

13. Where KappS fits in

App size and delivery modes sit in the same operational chain as the developer account, the payments profile and the tax information: any one of them can quietly hold up a release. KappS helps developers prepare and submit compliant material across that chain — including bundle and delivery configuration reviews, where the difference between an install-time pack and a fast-follow pack is measured in install conversion, not in megabytes.

What we do not do is work around the store. Size limits, delivery declarations and data safety answers are checked by Google against the artifact you actually shipped; a listing that promises something the bundle does not do is a fast route to a rejected release or a suspended account, and it is not a service we offer. The whole trick is the one described above: build the bundle honestly, declare what it really contains, and respect the limits.

Sources (Google official documentation): About Android App Bundles (developer.android.com/guide/app-bundle); Play Console Help — Optimise your app's size and stay within Google Play app size limits (support.google.com/googleplay/android-developer/answer/9859372); Configure the base module; Play Asset Delivery; Play Feature Delivery; bundletool (developer.android.com/tools/bundletool).