Architecture & Performance· 6 min read

Fast Images in React Native: expo-image, Caching and Sizes

Make React Native images fast: expo-image caching and placeholders, serving the right size and format, prefetching, lists, memory and common mistakes.

By

Full-Stack, Mobile & AI Engineer

Images are usually the heaviest thing a mobile app downloads and the most common reason a screen feels slow: thumbnails that pop in one by one, rows that jump when a photo loads, memory warnings on older Android phones, and launch screens waiting for a hero image. The fixes are mostly simple, and the payoff is visible to every user.

This guide covers React Native image performance in 2026: using expo-image well, serving the right size and format, caching and prefetching, images in long lists, and the memory problems that cause crashes.

Key takeaways

  • Use expo-image (it works in bare React Native too) for memory and disk caching, placeholders, transitions and modern formats.
  • Serve images at display size. A 3000-pixel photo in a 300-pixel slot wastes bandwidth, memory and decode time.
  • Use placeholders (blurhash or thumbhash, or a fixed-size box) so layouts don't jump while images load.
  • Prefetch images the user is about to see, and bundle the few images needed at launch.
  • Watch memory on Android: large images decoded at full resolution are a common cause of crashes.

Why images slow apps down

Each image costs three things: download (network time and data), decode (turning compressed bytes into pixels, on the CPU) and memory (decoded pixels take width × height × 4 bytes). A 4000 × 3000 photo needs about 48 MB in memory once decoded, regardless of how small it looks on screen. Multiply by a list of thumbnails and you can see where crashes come from.

expo-image: the sensible default

expo-image is Expo's image component, and it works in any React Native app. It handles caching, placeholders, transitions and modern formats out of the box:

import { Image } from "expo-image";

export function Avatar({ uri, blurhash }: { uri: string; blurhash?: string }) {
  return (
    <Image
      source={{ uri }}
      placeholder={blurhash ? { blurhash } : undefined}
      contentFit="cover"
      transition={150}
      cachePolicy="memory-disk"
      style={{ width: 48, height: 48, borderRadius: 24 }}
    />
  );
}

Older projects often used react-native-fast-image for caching. expo-image is the actively maintained choice today, so it's worth migrating when you touch image code.

Serve the right size and format

The biggest single win is usually on the server, not in the app:

  • Resize to display size (times the screen's pixel density). Use an image CDN or your storage provider's resizing so the app requests, for example, ?w=600 for a 300-point slot on a 2x screen.
  • Use modern formats. WebP is widely supported and much smaller than JPEG for the same quality; AVIF can be smaller still where supported.
  • Strip metadata and compress sensibly; most photos look identical at 75 to 85% quality.
  • Generate placeholders (blurhash or thumbhash) when images are uploaded, and send them with your API data.

Caching and prefetching

  • Cache in memory and on disk, so returning to a screen shows images instantly. expo-image's cachePolicy controls this.
  • Use stable URLs for the same image; changing query strings on every request defeats caching.
  • Prefetch images for the next screen, or the next page of a list, with Image.prefetch(urls) while the user is still on the current one.
  • Bundle launch images (logo, onboarding art, empty states) with the app instead of downloading them.

Images in long lists

Lists multiply every image cost:

  • Give every image fixed dimensions in the row's layout, so rows don't change height when images arrive.
  • Request thumbnails, not originals, for list rows.
  • Help recycling: in recycled lists such as FlashList, expo-image's recyclingKey stops a recycled row from briefly showing the previous row's image.
  • Lower priority for off-screen images and higher priority for what's visible.
From the field: Image optimisation was one of the three levers, with Hermes and cache-first fetching, that cut load time by about 60% (3.8 seconds to 1.5) across eight apps I migrated to the New Architecture. Right-sized images also matter for media-heavy products like Spoxio's athlete feeds with video highlights, where every row carries visual content.

Uploading images from the app

Performance starts at upload. If users can post photos (profiles, listings, feeds), don't send 12-megapixel originals straight from the camera:

  • Resize and compress on the device first with expo-image-manipulator, for example to a maximum of 2,000 pixels on the long edge at around 80% quality. Uploads become faster and cheaper on mobile data.
  • Upload directly to storage with a pre-signed URL from your server, rather than streaming large files through your API.
  • Generate thumbnails and placeholders on the server after upload, in the sizes your screens actually request.
  • Strip location metadata from photos unless your product needs it, for privacy as much as size.

Memory and crashes

  • Don't load full-resolution photos into small views. Ask the server for a smaller version, or downsample on the device.
  • Be careful with image-heavy screens that stay mounted, such as tab screens with large galleries; release images that aren't visible.
  • Test on a low-memory Android device. Out-of-memory crashes often appear only there.
  • Watch crash reports for memory-related crashes after shipping image-heavy features.

Common mistakes

MistakeEffectFix
Original uploads used as thumbnailsSlow lists, high memory, crashesServer-side resizing
No placeholder or fixed sizeLayout jumps as images loadPlaceholders and explicit dimensions
Cache-busting query stringsImages re-download every timeStable URLs; version only when content changes
Remote logo on the splash pathSlow startup on bad networksBundle launch images
PNG photosHuge filesWebP or AVIF

Pinch to zoom and image viewers

Full-screen viewers with pinch-to-zoom and swipe between photos are best built on Gesture Handler and Reanimated, so gestures run on the UI thread: a pinch gesture drives a shared scale value, a pan gesture moves the zoomed image, and both reset on double-tap. Maintained gallery libraries package exactly this; whichever you use, load a larger version of the image only when the viewer opens, not in the list.

FAQ

What is the best image component for React Native?

expo-image is the best general choice in 2026: it supports memory and disk caching, placeholders such as blurhash, smooth transitions and modern formats, and it works in bare React Native as well as Expo apps. Older projects using react-native-fast-image should consider migrating.

How do I cache images in React Native?

Use a caching image component such as expo-image with a cache policy of memory and disk, keep image URLs stable, and prefetch images the user is likely to see next. The built-in Image component's caching is more limited and platform-dependent.

Why does my React Native app crash with many images?

Usually because images are decoded at full resolution and use too much memory, especially on Android. Serve smaller images sized for display, use thumbnails in lists, and avoid keeping large galleries mounted when they're not visible.

Should I use WebP in React Native?

Yes, for photos and most graphics. WebP files are typically much smaller than JPEG or PNG at similar quality and are supported on iOS and Android. AVIF can be smaller still; check support for the platforms and versions you target.

Next steps

If your app's images load slowly or cause crashes on older phones, I can audit the pipeline from upload to screen and fix the biggest costs first. Get in touch, or see how I work as a React Native developer.

Sources

Bhuwanesh Sisodia

Bhuwanesh Sisodia

Full-Stack, Mobile & AI Engineer

Bhuwanesh Sisodia is a Full-Stack, Mobile & AI Engineer based in Mumbai, with 7+ years of experience and 50+ apps shipped to the App Store and Google Play. He works independently with startups and product teams worldwide.

About meGitHubLinkedInX

Related