Library / SDK
duguyihou/react-native-turbo-image avatar
duguyihou/react-native-turbo-image

react-native-turbo-image: Nuke and Coil behind one React Native component

Fast image loading for React Native

1,001 stars146 forksObjective-CMIT

At a glance

What is it?
TurboImage is a performant image component for React Native that delegates to Nuke on iOS and Coil on Android, so the caching, the pipeline and the request handling are the native libraries' work rather than a JavaScript implementation's. The component exposes a cache policy, three kinds of placeholder, and a set of image operations such as blur, tint and monochrome.
Who is it for?
Adopt react-native-turbo-image if you are building a React Native application with image-heavy screens, you want the caching behaviour of Nuke and Coil rather than a JavaScript implementation, and you are prepared to own a native dependency in both platforms. Do not adopt it if you need the component to run in Expo Go or in a JavaScript-only environment, because the native engines are not optional here.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 46 days ago.
What is it written in?
Mainly Objective-C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The heavy lifting is in two native libraries

TurboImage is described as a performant image component for React Native, and the sentence that follows is the whole architecture: it is powered by Nuke and by Coil.

Those are the established native image loading libraries, Nuke for iOS and Coil for Android, and this project is the React Native component in front of them. That matters for what you can expect from the component. The caching, the request coalescing, the disk cache and the pipeline configuration are the native libraries' behaviour, and the component is the bridge that exposes them to JavaScript.

The feature list follows from that arrangement:

- Support for the New Architecture, with a separate example application referenced for it. - Support for authorization headers. - Support for thumbhash, blurhash and a memoryCacheKey as a placeholder. - A memory cache, an aggressive LRU disk cache and an HTTP disk cache. - Prefetch, dispose, cleanMemoryCache and cleanDiskCache operations. - Written in TypeScript, Swift and Kotlin. - Support for special formats, namely SVG, GIF and APNG.

The three languages in that list are the shape of the project. The public surface is TypeScript, the iOS side is Swift and the Android side is Kotlin, and the component is a thin layer over two native engines rather than a from-scratch implementation.

The package is published on npm as `react-native-turbo-image`, it is MIT licensed, the homepage is the npm page, and the releases are frequent, v1.24.3 on 2026-07-23, v1.24.2 on 2026-06-06 and v1.24.1 on 2026-01-30, with the last push on 2026-09-06.

Installation and the smallest possible usage

Installation is the usual two steps for a React Native library with native code:

sh
npm install react-native-turbo-image

cd ios && pod install

The second step is the CocoaPods install for the iOS side, which is where the Swift implementation and the Nuke dependency are linked. There is no equivalent Android step in the README, because React Native's autolinking handles the Android module.

The usage is a single component with a source, a cache policy and a style:

tsx
import TurboImage from 'react-native-turbo-image';

<TurboImage
  source={{ uri: "https://cloud.githubusercontent.com/assets/1567433/9781817/ecb16e82-57a0-11e5-9b43-6b4f52659997.jpg" }}
  cachePolicy="urlCache"
  style={{ width: 240, height: 360 }}
/>;

The `source` is required and is an object containing a `uri` string. The `cachePolicy` is set explicitly in the example, and the default is also `urlCache`, so the example shows the default rather than an unusual choice.

The property table in the README then covers the rest: `style` takes an `ImageStyle`, `placeholder` shows something while loading, `resizeMode` accepts `contain`, `cover`, `stretch` or `center` and defaults to `contain`, `indicator` takes a `style` of `medium` or `large` and a `color`, and `fadeDuration` sets the transition duration with a default of 300 on iOS and 100 on Android.

The remaining properties are image operations rather than layout: `resize` scales an image to a given width preserving the aspect ratio, `blur` sets a blur radius, `monochrome` applies a colour, and `tint` applies a colour to every non-transparent pixel so the image takes the shape of that colour.

The cache policy is the property worth arguing about

The `cachePolicy` property determines how the image is cached, and it defaults to `urlCache`. The README links it to a dedicated section of the documentation, and the feature list describes the machinery behind it: a memory cache, an aggressive LRU disk cache and an HTTP disk cache.

Three caches with three different jobs is the reason the property exists. The memory cache is fast and small. The LRU disk cache holds decoded or downloaded data and evicts what has not been used recently. The HTTP disk cache stores what the server sent, which is what makes a second load of the same URL cheap and what makes the component resilient to a slow network on a repeat visit.

The component also exposes the operations that a cache needs to have. There is prefetching, so a screen can warm the cache before the user reaches the images. There is `dispose`, which releases the resources of an image that is no longer needed. And there are `cleanMemoryCache` and `cleanDiskCache`, which is what you call when a user signs out or when storage has to be reclaimed.

The `memoryCacheKey` appears in the feature list alongside the placeholder types, which suggests it serves two purposes: identifying a cached entry independently of the URL, and letting a placeholder be shared across the images that use the same key.

Placeholders, and the fading rule that comes with them

The placeholder support is more than a spinner. The feature list names thumbhash, blurhash and memoryCacheKey, and the property table describes `placeholder` as showing a placeholder while loading.

Thumbhash and blurhash are the two standard compact placeholder formats. A thumbhash is a small encoded representation of the image that a decoder can render as an approximate preview, and a blurhash is a set of components that describe the image's average colour and a rough gradient. Both are tiny, both are designed to be embedded in a response the client already has, and both give a recognisable shape rather than a grey box.

The interaction with the fade is the detail in the table. The `fadeDuration` entry says the transition duration of the image, and adds a note: to avoid flickering, it will be set to 0 when a placeholder is provided. The default is 300 on iOS and 100 on Android.

That is a sensible rule. A cross-fade from a placeholder that already looks like the image to the image itself produces a visible flash, because the two versions briefly disagree. With the duration set to zero the placeholder is replaced outright, and the screen looks stable while the real pixels arrive.

The consequence for an application is that a screen which uses placeholders will have hard cuts rather than fades, so the placeholder has to be a good approximation if the transition is going to look deliberate.

The published benchmark, and its own caveat

The README includes a benchmark section, and it starts with a caveat that is worth reading before the numbers: results may vary in real-world applications depending on factors such as network conditions, device specifications, image sizes and concurrent tasks.

The example is loading 120 images in a flat list, with the code in the example folder, and the two results are given as bare lines. The React Native built-in image took 15s, and react-native-turbo-image took 2s.

The shape of that comparison is the interesting part. Both numbers come from the same example application, and the two screens are named in the links, one of them the built-in image screen and the other a data cache screen. So the comparison is between the built-in component and this one, and it is the same 120 images.

What the numbers do not say is the device, the network, the image sizes, or whether the images were already in the cache. The caveat mentions network conditions, device specifications, image sizes and concurrent tasks, and a flat list is precisely the case where the cache and the request coalescing decide the outcome. Fifteen seconds versus two is a large difference, and it is the kind of difference that comes from the native engines doing the work rather than from JavaScript overhead alone.

The honest way to use the figure is as a reason to try the library on your own list screen with your own images, and to measure there. The library also says the same thing in a different way, by shipping the example application with those screens in it.

Where react-native-turbo-image is the wrong choice

The first wrong case is an environment without native modules. The component depends on Nuke and Coil, so it does not run in Expo Go and does not run in a JavaScript-only setup. If your pipeline is managed entirely through Expo, this library is not available to you, and the built-in `Image` is what you have.

The second is an application that needs one behaviour on both platforms. The two native engines do not have identical feature sets, and the property table shows where the README has to qualify things per platform. `monochrome` works with any colour on iOS and on Android Q and later, but only grayscale on Android before Q. The `fadeDuration` defaults differ, 300 against 100. A cross-platform design that assumes identical rendering is going to have exceptions to write down.

The third is a simple app. A handful of images on a couple of screens does not need an LRU disk cache and an HTTP disk cache, and the native dependency is a cost in build time, in binary size and in a second thing to upgrade when the React Native version moves.

The fourth is a team that cannot take a third-party native dependency into its build. The repository contains a `THIRD-PARTY-LICENSES` file, which is a good sign about compliance, but the Nuke and Coil licences and their versions become part of your distribution obligations, and the iOS side has to be rebuilt whenever the Nuke version moves.

The fifth is a project that needs an image format the native engines do not handle. SVG, GIF and APNG are called out as supported, which means other formats are not, and the list is the visible boundary of what the component can display.

Editorial conclusion

Adopt react-native-turbo-image if you are building a React Native application with image-heavy screens, you want the caching behaviour of Nuke and Coil rather than a JavaScript implementation, and you are prepared to own a native dependency in both platforms. Do not adopt it if you need the component to run in Expo Go or in a JavaScript-only environment, because the native engines are not optional here. Before you upgrade, compare the published `cachePolicy` values against the caching your current screens rely on, and set the placeholder deliberately, since the README notes that providing one changes the fade duration to zero to avoid flickering.

Frequently asked questions

How do I install react-native-turbo-image?

Run `npm install react-native-turbo-image`, then `cd ios && pod install` to link the iOS side. The Android module is picked up by React Native autolinking.

Which native libraries does TurboImage use?

The README describes it as a performant image component powered by Nuke and by Coil, and the project is written in TypeScript, Swift and Kotlin, with the component as the React Native layer over those two native engines.

What cachePolicy options does react-native-turbo-image offer?

The property is documented as determining how the image is cached and defaults to urlCache. The README lists a memory cache, an aggressive LRU disk cache and an HTTP disk cache, and the individual policy values are described in the linked documentation section.

Can I show a placeholder while an image loads?

Yes. The component supports thumbhash, blurhash and memoryCacheKey as placeholders, and the README notes that when a placeholder is provided the fade duration is set to 0 to avoid flickering.

Official sources

  1. duguyihou/react-native-turbo-image on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/duguyihou-react-native-turbo-image.svg)](https://hysenlabs.com/projects/duguyihou-react-native-turbo-image)

Was this useful?