RORK LABJP
PLAY — Google Play's target API level 36 requirement took effect yesterday, August 31. From today, new apps and updates must target Android 16VISIBILITY — Apps still on API 35 stay listed but disappear for users on newer Android versions. No error is raised; new installs simply fade, which makes the change easy to missEXTENSION — If you missed the deadline, an extension through November 1, 2026 can be requested in Play Console — best filed alongside a concrete migration planAPPLE — On the Apple side, the event lands September 9 and iOS 27 is reported to ship September 14. Testing generated apps on iOS 27 hardware before release week is time well spentEXPO — Expo released expo-paste-input on August 28, a native module that brings image, GIF, and sticker paste to React Native TextInputEAS — EAS Observe reached general availability on August 20, putting crash and performance monitoring on the same EAS platform as builds and updatesPLAY — Google Play's target API level 36 requirement took effect yesterday, August 31. From today, new apps and updates must target Android 16VISIBILITY — Apps still on API 35 stay listed but disappear for users on newer Android versions. No error is raised; new installs simply fade, which makes the change easy to missEXTENSION — If you missed the deadline, an extension through November 1, 2026 can be requested in Play Console — best filed alongside a concrete migration planAPPLE — On the Apple side, the event lands September 9 and iOS 27 is reported to ship September 14. Testing generated apps on iOS 27 hardware before release week is time well spentEXPO — Expo released expo-paste-input on August 28, a native module that brings image, GIF, and sticker paste to React Native TextInputEAS — EAS Observe reached general availability on August 20, putting crash and performance monitoring on the same EAS platform as builds and updates
Articles/Dev Tools
Dev Tools/2026-07-15Advanced

Half the Bytes, the Same Wait: What AVIF Actually Cost My Wallpaper Apps

Switching to AVIF cut my transfer bill in half and did nothing for perceived speed. Here is the transfer-versus-decode breakdown, the Accept-negotiation trade-off, per-device fallback tiers, and the staged migration order that finally worked across six apps.

Rork547Expo193image formatsAVIFCDN2

Premium Article

The R2 bill said AVIF would halve my costs

I run six wallpaper apps as an indie developer. The images do not ship inside the binary — they come from Cloudflare R2 on demand. One month the transfer line item came in higher than I had planned for, and nine tenths of it was thumbnails and full-size images.

AVIF halves your bytes at the same visual quality. That claim is everywhere, and in my case it held up. I re-encoded 400 wallpapers at 2,796×1,290 from JPEG quality 82 to AVIF quality 50, and 1.41 GB became 0.68 GB. A 52% reduction.

Then I shipped it to real devices and scrolled the gallery. Nothing felt faster. On a Pixel 4a it felt distinctly worse.

I had been staring at a single number — bytes transferred — and assuming that shrinking it would shrink the wait. It does not, and the reason turned out to be worth writing down.

Perceived speed is transfer plus decode

An image reaches the screen through at least three stages: pulling it over the network, unpacking the compression into a bitmap, and drawing it. Change the format and the first stage shrinks while the second one grows.

onLoadStart and onLoad from expo-image collapse all three into one number, so I had to split them apart. Transfer time comes from R2 logs; decode time is the gap between the bytes arriving and the bitmap being ready on device.

Here are the medians from 20 representative images, three runs each, over Wi-Fi measured at 92 Mbps.

FormatAvg sizeTransferDecodeTotal
JPEG q823.6 MB312 ms48 ms360 ms
WebP q802.4 MB208 ms71 ms279 ms
AVIF q501.7 MB147 ms194 ms341 ms

AVIF saved 165 ms on the wire and handed back 146 ms at the decoder. Net gain: 19 ms. My bill dropped by half; my readers waited exactly as long as before.

The faster the connection, the worse this trade looks. Repeating the measurement throttled to 14 Mbps flipped it — AVIF totalled 1,340 ms against JPEG's 2,105 ms, a clear win. Format rankings invert depending on the device and the network. Pick one based on a single average and you are quietly taxing one half of your audience to pay for the other.

On older hardware, decode hurts twice

The Pixel 4a decoded AVIF in roughly 380 ms per image, about 1.9× the 194 ms I measured on an iPhone 15 Pro. Hardware without an AVIF decoder falls back to the CPU.

During a scroll, several images decode at once, so a slow decoder does not just delay one tile — it drags the UI thread with it. Frame drops on the Pixel 4a went from 3.1% to 11.7% after the AVIF rollout. I had made the experience worse in exchange for a cheaper invoice.

The memory side does not improve either. A decoded bitmap is the same size regardless of the source format, which is the same wall I described in the wallpaper cache memory bloat notes. Changing formats reclaims zero bytes of RAM.

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
Why a 52% drop in transfer bytes produced only a 19ms improvement, shown with the transfer and decode times measured separately
Accept negotiation versus a manifest with per-format URLs, compared on CDN hit rate, rollback cost, and what each can express
Device-tier fallback logic and the 5-step migration order that cut transfer 38% without regressing frame drops on older hardware
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 $15 for lifetime access
View Membership →

Related Articles

Dev Tools2026-08-22
Every bulk replace exited zero. The damage was in the lines I did not delete
Run a bulk replace over generated code and the breakage lands on the neighbouring lines, not the matched ones. Here is what broke in a live project, and a dependency-free guard that checks the invariants a replace must preserve.
Dev Tools2026-08-21
The four acceptance checks I still run after the build turns green
A successful build does not mean a shippable build. Here are the four failure classes an AI build loop cannot see, and a dependency-free script that inspects the artifact itself before you submit.
Dev Tools2026-08-20
A beta-SDK build can reach TestFlight, but it can't reach review
Builds made with a beta Xcode can be distributed through TestFlight, but they cannot be submitted for App Store review. Here is how to check which SDK produced your build, and how to protect your release profile in eas.json.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →