Device Storage Budget
also called On-Device Footprint Ceiling, Local Store Cap
A designed ceiling on the bytes an application occupies on a user's device, treated as a requirement because exceeding it produces uninstalls and failed updates rather than an error anyone can see.
An offline-first app is a database with a user interface, and databases grow: cached images, a local working set, attachments, a sync log, a send queue, queued analytics. None of it errors and none of it appears in a crash report, so on a developer's phone with 200 GB free it is invisible for years.
Then a user on a 32 GB device gets a low-storage warning, opens the settings screen that lists apps by size, finds yours at the top, and taps Clear Data or Uninstall. An oversized local store does not degrade the product; it removes it - hardest on the devices a growth market consists of.
Why it matters
The failure is invisible from inside the app. No exception, no latency change, and the churn looks like an ordinary uninstall, so teams learn about it from store reviews rather than telemetry.
Storage pressure also breaks the update path: a device without space to stage a new build does not get it, adding your own app to the version long tail.
The third cost is correctness. Platform cache directories are reclaimable by the operating system at any time, without your process running and with no notification. If the send queue lives there, the user's work disappears between sessions and the logs show nothing.
Implementation patterns
- Set the number before you need one, split by class - cache, durable store, media - since eviction policies differ.
- Least-recently-used eviction driven by a size cap, not a TTL. A TTL bounds freshness; only a cap bounds size.
- Cache the variant you render, not the full-resolution original behind a 120-pixel thumbnail.
- Put the outbox in the app's own data directory, and audit every offline write path for where its durable record lands - including the database journal and attached media.
- Alert on the p99 by device model, not the mean, which is dominated by users who are fine.
Industry example
Zomato's June 2025 engineering post on its consumer Android app gives the shape and some defensible numbers. Download size went from 23 MB to 15-16 MB, and a cache that had been reaching 600-700 MB was capped at 120 MB after the team found about 100 MB sufficient for the home-page thumbnails that drive the first screen; leftover temporary files accumulating in the cache were also fixed.
The mechanical wins are available to anyone: app bundles gave up to 22% off download size, and converting PNGs to WebP where smaller gave roughly a tenfold reduction for blurred images. The lesson is the ratio rather than the figures: the cache consumed five to six times what the screens it served needed, and nothing was responsible for noticing.
Failure scenarios
- An unbounded image cache growing for the life of the install, with churn as the only feedback.
- The send queue in the cache directory, so the operating system discards work the user believes is saved.
- Downloaded media with no retention rule - usually the largest category.
Trade-offs
| Choose | Gains | Pays |
|---|---|---|
| Hard ceilings with LRU eviction | bounded footprint - no storage-driven churn - predictable updates | re-fetches after eviction - more network use - a ceiling someone must justify |
| Unbounded local store | fastest repeat access - full offline depth | uninstalls on low-end devices - failed updates - no telemetry |
| Everything in the cache directory | stays off the storage list | user work can vanish silently |
When not to use it
When the install base is uniformly high-storage hardware. If the tenth percentile of free storage across your users is 40 GB, a 600 MB footprint costs nothing.
When the data must be local and complete. A field-survey app working for a week underground needs its whole working set on the device; the answer is a larger explicit budget declared to the user, not evicting data the product depends on.
And do not let a budget become an argument for deleting small things. A few hundred kilobytes of order history powering a real offline screen is not the problem: storage is not the enemy, unbounded storage is.
Interview question
Q: Support reports users on cheap Android devices uninstalling after a few weeks, and nothing in your crash or latency telemetry has changed. What would you look at, and what would you change first?
What a strong answer covers: suspecting footprint because the failure has no error signal · measuring p99 on-device size by device model and free storage at install, not the mean · separating cache from durable state and checking whether the outbox sits where the OS can reclaim it · a measured LRU ceiling rather than a TTL · retention rules for downloaded media · and arguing it with uninstall rate by free-storage bucket.
Quick check
Quiz: Why is an unbounded on-device cache more dangerous than a slow one? — It produces no error, no latency change and no crash. The user sees a low-storage warning and clears data or uninstalls, so the only signal is churn weeks later.
Flashcard: Which directory must an offline-first app's send queue never live in? — The platform cache directory, which the operating system can reclaim at any time without the app running and with no notification, so unsent work disappears with nothing in the logs.