# react-native-fast-image: the caching image component worth knowing about

> A TypeScript wrapper around SDWebImage and Glide that fixes flickering, cache misses and slow cached loads in React Native lists, and the recycling and cache props that make it work.

**DylanVann/react-native-fast-image** — Performant React Native image component.

- Repository: https://github.com/DylanVann/react-native-fast-image
- Stars: 8,411 · Forks: 1,523
- Language: TypeScript
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/dylanvann-react-native-fast-image

## What it actually wraps on each platform

The premise is a single sentence in the README: `FastImage` is a wrapper around SDWebImage on iOS and Glide on Android. That framing matters more than the feature list, because it tells you where the behaviour comes from. Cache semantics, request priority, request coalescing and disk layout are decided by those two libraries, not by the JavaScript in `src/`. The TypeScript layer is a props translation surface.

The README opens by conceding that React Native's `Image` already handles caching in a browser-like way when the server returns proper cache control headers. The complaint list that follows is worth reading literally, because it defines the scope of the problem: flickering, cache misses, low performance loading from cache, and low performance in general. If your images already come back with good headers and your lists do not recycle rows, the gap between `Image` and `FastImage` is much smaller than the star count suggests.

The topic tags match that structure: `sdwebimage`, `glide`, `image-cache` and `cocoapod`. The tree shows native source in `ios/` and `android/` alongside three example apps, including `ReactNativeFastImageExampleLegacy` and `ReactNativeFastImageExampleServer`.

## Installing it and rendering the first image

The install is two commands, and the second one matters because this is a native module. Adding the package without running pod install gives you a JavaScript component that cannot find its native counterpart.

```bash
yarn add react-native-fast-image
cd ios && pod install
```

The README also states a hard floor: React Native 0.60.0 or higher is required for the most recent version. That number matters because it is the boundary where the old bridge gave way to the new architecture, and a component with native views straddling that line needs the autolinking path to be understood.

The first component is small enough to hold in your head:

```jsx
import FastImage from 'react-native-fast-image'

const YourImage = () => (
    <FastImage
        style={{ width: 200, height: 200 }}
        source={{
            uri: 'https://unsplash.it/400/400?image=1',
            headers: { Authorization: 'someAuthToken' },
            priority: FastImage.priority.normal,
        }}
        resizeMode={FastImage.resizeMode.contain}
    />
)
```

Three of those props do the interesting work. `headers` passes an Authorization token to the native loader, which is the documented route for private image endpoints. `priority` puts the request in an ordered queue. `resizeMode` has the same four values the platform component exposes, with `cover` as the default.

## cacheControl decides whether the HTTP cache is consulted at all

The default cache behaviour surprises people, because `FastImage.cacheControl.immutable` is the default and it means the image only updates when the url changes. The HTTP cache is not involved. Images are keyed by url and treated as permanent.

`FastImage.cacheControl.web` turns on ordinary header-based caching. The README is specific about the Android consequence: those responses land in a 50 MB HTTP cache, or in the app's own if its OkHttp client already has one. `FastImage.cacheControl.cacheOnly` is the third option and it makes no network requests at all, which is what you want in a test or a screenshot run.

There is a fourth, more interesting prop in the current version. `cacheKey` overrides the key an image is stored under, which is the fix for signed urls that change on every request while the bytes behind them do not:

```jsx
<FastImage
    source={{
        uri: signedUrl,
        cacheKey: `avatar-${user.id}-${user.avatarUpdatedAt}`,
    }}
/>
```

The README's warning is the part to internalize: use something that identifies the image, and change it when the image changes. A cache key that stays constant across an avatar update means the old avatar keeps showing, with no error anywhere. The prop is documented as unused with `cache: 'web'`, since that mode is keyed by url and follows the HTTP cache instead.

## recyclingKey is the prop that decides whether a list looks correct

React Native reuses views. In a FlashList or recyclerlistview row, the same view instance gets pointed at a different item's data, and while the new image loads, the old one is still on screen. The README treats this as the default behaviour and mirrors what `<img>` does in browsers: when `source` changes, the image that is showing stays until the new one has loaded.

That is correct for a page and wrong for a list. `recyclingKey` is the fix, and it works by clearing the image the moment the key changes rather than holding it:

```jsx
<FastImage recyclingKey={item.id} source={{ uri: item.imageUrl }} />
```

Set it to something that identifies the content, such as the item's id, and a recycled row drops back to `defaultSource` or blank instead of showing the previous row's picture. The README draws the distinction from changing `key` explicitly: changing `recyclingKey` keeps the view, which is the entire point of list recycling.

`defaultSource` is the asset shown during that window, loaded with `require(...)`. One documented limitation is worth knowing before you debug it: on Android, `defaultSource` does not work in debug mode, because assets are served from the dev server while the loading functions only read from `res`. It works in release builds, which makes for a confusing bug report if nobody has seen that note.

## Priority, preloading and keeping decoded photos off the heap

Priority is a queue, not a hint. The README describes `FastImage.priority.high` as loading before images in a similar context with low or normal priority, with `normal` as the default. In a feed screen that is the difference between the header image arriving with the first frame and arriving after everything below it.

The companion to priority is preloading, and the release notes show it being tightened rather than expanded. Version 8.16.1, published 2026-09-28, carries a fix titled make preload follow `source.cache`, which means the preload path now honours the cache mode you chose instead of assuming one. Version 8.16.2 the same day clears the HTTP cache of web images inside `clearDiskCache`. Version 8.17.0, also 2026-09-28, added `source.memoryCache`.

That last prop is the memory story. Set to `false`, a decoded image stays on disk only: the view does not leave it in memory once it stops showing it, and `FastImage.preload` downloads without decoding. The README puts a number on why you would want this, saying a decoded photo can take tens of MB. The cost is that an image shown a second time gets decoded from disk again, which is the right trade for a full-screen photo shown once and the wrong trade for a list you scroll back through.

## Where the README stops and the extra docs begin

The README is thorough on props and silent on several things you would want to know before committing. There is no section on the new architecture, no compatibility table for React versions, and no guidance on whether FastImage works with Expo. The repository tree hints at the answer to the last one rather than stating it: the podspec and native source mean this is a package with native code, which in Expo terms means a development build rather than a managed one.

Two separate documents are linked rather than included. `docs/app-glide-module.md` is flagged with a warning that you might have problems if you do not read it, which is the note to follow if your Android app already defines its own Glide module, and `docs/` sits in the tree alongside that reference. The `maestro/` directory suggests end-to-end tests run against the example apps.

The package itself is MIT and Apache-2.0 combined, declared as `(MIT AND Apache-2.0)`, with `main` pointing at a CommonJS build and `module` at an ES module build, plus a `typings` entry. The build runs `tsc` and then rolldown, tests run under bun, and releases come from semantic-release. The last push was 2026-09-28, the same day as all three recorded releases, which is a project shipping at a fast clip on a stable major version of 8.

## Conclusion

The case for this library rests on two things the built-in `Image` does not do well: a real disk and memory cache you control, and a priority and preload queue so the image above the fold arrives before the one below it. `recyclingKey` is the prop that decides whether it is pleasant or broken in a recycled list, and it is the one most integrations leave unset. The README does not discuss the new architecture at all, and with 8414 stars and 1523 forks there are many integrations to compare against, so on a current app the honest first question is whether the platform component has caught up. Reach for it when you control the server's cache headers, when lists reuse rows, and when memory pressure on decoded full-screen photos is real.

## FAQ

### What is the difference between react-native-fast-image and the built-in Image component?

The built-in component caches in a browser-like way when the server sends proper cache control headers. FastImage wraps SDWebImage on iOS and Glide on Android, which gives it aggressive caching, request priority, preloading, authorization headers and GIF support. Its cache is keyed by url and treats images as immutable by default rather than following HTTP headers.

### Why does a recycled list row show the previous row's image?

Because the view is reused and the previous image stays on screen until the new one loads, the same as an `<img>` in a browser. Set `recyclingKey` to something identifying the content, such as the item's id, and the image clears to `defaultSource` or blank as soon as the key changes. Changing `key` instead would recreate the view, which defeats the purpose of recycling.

### How do I stop FastImage using too much memory with large photos?

Set `source.memoryCache` to false. The decoded image then stays on disk only, is not left in memory once the view stops showing it, and preload downloads without decoding. A decoded full-screen photo can take tens of MB, so this is worth it for images shown once, and it costs you a re-decode from disk for images shown again.

## Sources

- [DylanVann/react-native-fast-image on GitHub](https://github.com/DylanVann/react-native-fast-image)
- [Issues](https://github.com/DylanVann/react-native-fast-image/issues)
- [License: MIT](https://github.com/DylanVann/react-native-fast-image/blob/main/LICENSE)
- [README](https://github.com/DylanVann/react-native-fast-image/blob/main/README.md)
- [Releases](https://github.com/DylanVann/react-native-fast-image/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dylanvann-react-native-fast-image
