◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 36 days left. If your app calls it, check the migration target●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 36 days left. If your app calls it, check the migration target●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/App Dev
◇ App Dev/2026-06-09Advanced

Keeping a wallpaper app's binary small: moving images out of the bundle

Wallpaper apps bloat every time you add images. Here is where I draw the line between bundled and remote assets, how I keep first paint fast with prefetching, and the format work that cut transfer size to a third — with real numbers.

app-sizewallpaper-appasset-deliveryExpo227performance11

✦ Premium Article

The first build of my wallpaper app shipped at about 16MB. Then I started adding new wallpapers every season, and six months later the bundle had crossed 90MB. Long before I hit the App Store's cellular download limit, a different problem showed up: the first launch got visibly slower, and reviews started mentioning that the app "felt heavy" — people were reacting to the size shown on the store page.

I have been building wallpaper apps on my own for a long time, and right now I run six of them in parallel. Every one of them lives on the same tension: the urge to add more images versus the need to keep the binary light. Each time I add a new season's wallpapers, I come back to that same trade-off. Here I want to share how I resolved it in the architecture, with the code I actually run and the before/after numbers.

Why size suddenly becomes a problem for wallpaper apps

In a typical productivity app, images are just the icon and a few illustrations. In a wallpaper app, the images are the product. A single high-resolution wallpaper (1290×2796 for an iPhone 15 Pro Max, in Display P3) can exceed 10MB uncompressed. Bundle a hundred of those and the binary alone approaches 1GB.

When size grows, the pain shows up in three places. First, store conversion: the App Store product page shows the download size, and without Wi-Fi that number makes people hesitate. On one app, the version that dropped the binary from 90MB to 28MB saw install completion (store view to completed install) improve by about 14%. Second, first launch: a large bundle of images raises build time and runtime memory, especially when you stuff an asset catalog full on iOS. Third, update agility: pushing a 30MB+ re-download to every user just to add five wallpapers is far too heavy. Wallpapers are content; they update on a different rhythm than code.

Where to draw the bundled/remote line

"Just make everything remote" would be easy to say, but then the grid is blank on first launch and the experience falls apart. I draw the line on two axes.

The first is contribution to the launch experience. Anything on the very first screen — the onboarding background, the handful of thumbnails visible in the first grid — gets bundled, because a network wait there leads straight to drop-off. The second is update frequency: seasonal collections and new drops go remote, while things that never change (the logo, placeholders) stay bundled.

In practice, my split looks like this:

  • App icon, splash, UI icons: bundled (a few hundred KB)
  • Only the thumbnails of the first 6–8 wallpapers visible in the opening grid (not full resolution): bundled
  • Full-resolution wallpapers, extra collections, seasonal sets: all remote

With just this policy, the only thing bundled is thumbnails and UI assets, and the binary shrinks dramatically. On a real app I cut the IPA from 90MB to 28MB — about a 69% reduction.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦A concrete rule for splitting bundled vs remote assets along two axes: launch experience and update cadence
✦A manifest-plus-prefetch implementation that cut the IPA by over 60% without slowing first paint
✦HEIC/WebP, Display P3 and downsampling steps that reduced per-image transfer to one third
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

◇ App Dev2026-08-05
A JSON File 19% Smaller That Ships Only 3% Smaller — Measuring Catalog Payloads Against gzip
Five payload formats measured on a 20,000-item wallpaper catalog. Key shortening saves just 3.2% after gzip, while a columnar layout cuts 26.8%. Real numbers for Brotli, paging, and JSON.parse time.
◇ App Dev2026-10-22
Expo SDK 58 With Stripe: pod install Stops, and Whether to Turn Off Precompiled Modules or Wait
useFrameworks is already dynamic, yet pod install says Stripe is static and the SDK 58 iOS build stops. The reported conditions, three ways out, and a small script to check your own project first.
◇ App Dev2026-10-18
It Ran Fine in Debug, but the Release Build Died on Launch with a Resource Not Found. A File I Looked Up by Name Had Been Shrunk Away
A release-only crash at launch, caused by images and sounds looked up by a name string being removed by resource shrinking. A keep.xml written at prebuild, plus a post-build check that confirms it worked.