Optimizing Image Caching Strategies with FastImage
AI generated
RN
native
React Native / Performance
Image Caching Strategies
Optimizing with FastImage once the built-in Image component runs into limits

A product list with a hundred thumbnails or a feed full of high-resolution photos quickly exposes the limits of React Native's built-in Image component, which lacks aggressive caching. FastImage closes that gap with native disk and memory caching logic. This article covers the limits of the built-in component and how to configure FastImage in practice.

9 min read FastImage Image Caching

1. Limits of the built-in Image component

React Native's built-in Image component uses different, fairly simple caching mechanisms on iOS and Android that offer little in the way of configuration. On iOS it falls back on the system-wide URL cache, shared with countless other requests across the app, leaving little control over how long a specific image actually stays cached.

In practice this means images in long lists, say a product catalog or a social feed, visibly reload on rescroll even though they were displayed moments earlier. For a handful of images on simple screens that's not an issue, but for large image galleries it has a direct impact on the app's perceived performance.

2. How FastImage solves the caching problem

FastImage replaces the native image loading logic with SDWebImage on iOS and Glide on Android, two established, specialized libraries that ship with a two-tier cache spanning memory and disk out of the box. An image that has already been loaded once can be shown instantly from memory or disk on the next render, without another network request.

FastImage also automatically deduplicates parallel requests for the same image URL: if several list items rendered at the same time request the same image, only a single network request actually goes out, while every waiting component receives the result of that same request once it arrives.


import FastImage from 'react-native-fast-image';

function ProductThumbnail({ uri }: { uri: string }) {
  return (
    <FastImage
      style={{ width: 120, height: 120, borderRadius: 8 }}
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
    />
  );
}

3. Cache control strategies in detail

FastImage offers three cache control modes that precisely determine how HTTP cache headers get handled. The immutable mode assumes an image under the same URL never changes, which is ideal for product images with unique, versioned filenames, and delivers the highest cache hit rate without any repeated header check.

The web mode fully respects the Cache-Control and Expires headers sent by the server, which suits content that can occasionally change, such as user avatars. The cacheOnly mode blocks every network request and only returns already cached images, which fits offline views where no fresh download is desired.

4. Prioritization in long lists and feeds

The priority property controls which images get loaded first when many requests are pending at once, for example while fast-scrolling through a FlatList. Images visible in the current viewport should get high priority, while images outside the visible area that are only preloaded can be assigned low priority.

This prioritization noticeably reduces time-to-visible-image, because the native loading queue works through the more urgent requests first instead of strictly loading every image in render order. For very long lists, it's also worth skipping preloading altogether for images far outside the visible area, avoiding unnecessary network and memory usage.

5. Preloading for better perceived performance

FastImage exposes a static preload method that loads a list of image URLs ahead of time, before the corresponding components are even rendered. That's particularly useful for the next step in a known user flow, for example preloading detail images as soon as a product list is displayed.

It matters to use preloading in a targeted, bounded way instead of loading every image in an app in the background indiscriminately. Uncontrolled preloading can block available network throughput for actually visible content and unnecessarily drive up the app's memory footprint.


// Preload the next detail images as soon as the list becomes visible
useEffect(() => {
  const preloadTargets = products.slice(0, 5).map((p) => ({ uri: p.detailImageUrl }));
  FastImage.preload(preloadTargets);
}, [products]);

6. Controlling memory usage and cache limits

An aggressive image cache can itself become a performance problem if left unbounded, especially on older devices with limited memory. FastImage largely leaves the concrete size limits to the native SDWebImage and Glide libraries, both of which ship with sensible defaults but can be fine-tuned through native configuration if needed.

In practice it's usually enough to keep the defaults and instead control image size at the source: a thumbnail should not be loaded at the original's full resolution, but should already arrive pre-scaled via an image server or CDN transformation, so the cache isn't filled unnecessarily with oversized data.

7. Cache invalidation and manual clearing

For cases where an image under the same URL genuinely changes, for example an updated user profile picture, the immutable mode falls short because it ignores exactly that change. Better options are a cache-busting parameter in the URL or an explicit call to FastImage.clearMemoryCache and FastImage.clearDiskCache after a successful upload.

A full cache reset should be used sparingly, since it discards every previously cached image and briefly generates increased network traffic again. For isolated changes, a cache-busting parameter that only affects the specific URL is usually the more targeted and resource-friendly solution.

8. Combining FastImage sensibly with FlatList and FlashList

FastImage delivers its biggest benefit combined with a FlatList or the more performant FlashList, since fast scrolling mounts and unmounts many image components at once. Without a disk cache, every image that becomes visible again would have to be fully reloaded from the network, causing visible reloading during fast scrolling.

It's also worth setting the list's getItemLayout property when image sizes are known in advance, so the list itself renders more efficiently and FastImage doesn't trigger extra, unnecessary loading cycles from frequent re-layouts.

9. When the built-in Image component is actually enough

Not every app needs FastImage: with just a few static images per screen, say a logo or a single hero image, React Native's native image loading logic usually shows no noticeable downside, and the extra native dependency barely pays off in such cases.

But once more than a handful of network images are visible at once, users frequently navigate back and forth between views showing the same images, or a scrollable list of thumbnails sits at the core of the app, the benefit of FastImage clearly outweighs the added complexity.

Cache mode Behavior Typical use case Main limitation
immutable Ignores HTTP cache headers, maximum hit rate Product images with versioned, unique URLs Changes under the same URL go undetected
web Respects Cache-Control and Expires headers Content that occasionally changes, e.g. avatars Cache hit rate depends on server headers
cacheOnly No network request, only already cached images Offline views without a fresh download New, not-yet-cached images stay invisible
priority.high Preferred processing in the loading queue Images visible in the current viewport Too many high-priority requests cancel out the effect
priority.low Deferred processing in the loading queue Preloaded images outside the visible area Can be significantly delayed on weak connections

Mironsoft

React Native app development and Magento integration

A mobile app for the Magento shop that actually runs smoothly?

We build React Native apps cleanly connected to the Magento REST or GraphQL API, from the first line of code to publishing on the App Store and Google Play.

App Concept

Plan the architecture and feature scope of a Magento-connected app together.

Magento API Integration

Cleanly connect product catalog, cart, and checkout to the shop API.

Store Publishing

Guide the App Store and Google Play release process without pitfalls.

10. Summary

Image Caching with FastImage: Key Takeaways

Built-in component has limits

The built-in Image component offers little configurable caching and causes visible reloading in long lists.

FastImage uses SDWebImage and Glide

Two-tier memory and disk cache plus automatic deduplication of parallel requests for the same URL.

Set priority and cache mode deliberately

Visible images get high priority, versioned URLs benefit from the immutable cache mode.

Use preloading sparingly

Targeted preloading for the next user step pays off, uncontrolled preloading blocks network and memory.

11. FAQ: Image Caching with FastImage: Key Takeaways

1Why does React Native's built-in Image component often fall short?
Because its caching differs between iOS and Android and offers little configuration, which causes visible reloading in long lists with many images on rescroll.
2Which native libraries does FastImage use under the hood?
SDWebImage on iOS, Glide on Android, both established libraries with a built-in two-tier memory and disk cache.
3What does the immutable cache mode mean?
It assumes an image under the same URL never changes, delivering the highest cache hit rate, but only fits images with unique, versioned URLs.
4How does deduplication of parallel image requests work?
If several components rendered at the same time request the same image URL, FastImage only sends a single network request and distributes the result to every waiting component.
5When should priority.high be used instead of priority.normal?
For images sitting in the current visible viewport, so the native loading queue processes them before non-visible, preloaded images.
6How do you handle images that change under the same URL?
The immutable mode ignores such changes. A cache-busting parameter in the URL or an explicit call to clearMemoryCache and clearDiskCache fits better.
7Is unlimited preloading advisable?
No, uncontrolled preloading can block network throughput for actually visible content and unnecessarily increase the app's memory usage.
8Does every React Native app need FastImage?
No, with a few static images per screen the built-in component usually shows no noticeable downside. FastImage pays off mainly for large image galleries and feeds.
9How can the image cache be fully reset?
Through the static clearMemoryCache and clearDiskCache methods, which should be used sparingly since they discard every cached image.
10How should FastImage be combined with FlatList or FlashList?
Ideally together with a correctly set getItemLayout property, so the list renders efficiently and FastImage doesn't trigger unnecessary loading cycles from frequent re-layouts.