Why Image Optimization Matters
Images are typically the largest assets in a mobile app, often accounting for 50-80% of the total bundle size or network data usage. Unoptimized images lead to larger app downloads, slower screen loads, higher memory usage, and increased data costs for users on metered connections.
Optimizing images is one of the highest-impact performance improvements you can make.
Image Formats
JPEG
The classic lossy format. Good for photographs and complex images with many colors. Adjustable quality (60-85% is the sweet spot for mobile). No transparency support. Progressive JPEG loads in passes (blurry to sharp), improving perceived performance.
PNG
Lossless format with transparency support. Best for icons, logos, and images with sharp edges. Much larger than JPEG for photographs. Tools like pngquant reduce PNG size by 60-80% with minimal quality loss.
WebP
Google's modern format supporting both lossy and lossless compression with transparency. 25-35% smaller than JPEG at equivalent quality. Supported on iOS 14+, Android 4.0+. The recommended default format for mobile apps in 2026.
AVIF
The newest format, based on AV1 video codec. 30-50% smaller than WebP at equivalent quality. Supported on iOS 16+, Android 12+. Slower to encode than WebP. Best for pre-processed, pre-stored images.
SVG
Vector format for icons, logos, and illustrations. Resolution-independent, tiny file size for simple shapes. React Native: use react-native-svg, Flutter: built-in support.
Responsive Image Loading
Resolution-Based Loading
Load different image resolutions based on the device's pixel density:
- @1x, @2x, @3x (iOS naming convention)
- mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi (Android resource folders)
Serving a @3x image to a @1x device wastes 9x the pixels.
Size-Based Loading
Load images at the size they will actually be displayed. If a thumbnail is 100x100 points, do not load a 2000x2000 original. Use image CDN resize parameters (Cloudflare Images, Imgix, Cloudinary).
Progressive Loading
Show a low-quality placeholder while the full image loads:
- Blur hash: A compact string that decodes to a blurred preview
- LQIP (Low Quality Image Placeholder): A highly compressed small version
Caching Strategies
In-Memory Cache
Keep recently displayed images in RAM for instant re-display. Major image libraries handle this automatically:
- React Native: expo-image (recommended), react-native-fast-image
- Flutter: cached_network_image
- iOS: Kingfisher, SDWebImage, Nuke
- Android: Coil (Compose), Glide
Disk Cache
Store downloaded images on disk to avoid re-downloading. Most image libraries manage this automatically. Set appropriate cache size limits (100-500 MB typical) with LRU eviction.
CDN (Content Delivery Network)
Serve images from edge servers close to the user. Handles format negotiation (serve WebP to supported clients, JPEG to others) and on-the-fly resizing. Popular options: Cloudflare Images, Imgix, Cloudinary.
Bundled vs. Remote Images
Bundled (In-App)
Available offline with no loading delay, but increases download size and cannot be updated without an app update. Best for: app icon, splash screen, onboarding illustrations, small UI icons.
Remote (Downloaded)
Keeps app size small but requires network connectivity (or disk cache). Best for: user-generated content, product photos, marketing banners.
Compression Tools
- Squoosh (web): Compare formats and quality levels side by side
- TinyPNG/TinyJPG: Batch compression API
- ImageOptim (macOS): Lossless optimization for bundled assets
- Sharp (Node.js): Server-side image processing and conversion
Best Practices
- Default to WebP for all images in 2026
- Use SVG for icons and simple illustrations
- Always specify image dimensions to prevent layout shifts
- Implement progressive loading with blur hashes for remote images
- Set up a CDN with on-the-fly resizing
- Compress bundled assets as part of your build pipeline
- Monitor image-related memory usage on low-end devices
- Lazy-load off-screen images (FlatList in RN, LazyColumn in Compose do this automatically)