React Native: expo-image, BlurHash and Video

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

Baseline date: 2026-10-07. Versions on npm on that date: expo-image 57.0.5, react-native-blurhash 2.1.3, react-native-fast-image 9.1.0, react-native-video 6.19.3. The core Image component and the sizing rules are in Images and Icons. This page covers what a media backend needs on top: caching, placeholders and video. Check the expo-image documentation for the SDK version you use.

expo-image wraps SDWebImage on iOS and Glide on Android, supports modern formats (WebP, AVIF where the platform allows, HEIC on iOS, SVG), and has first-class placeholder and caching options. It works in bare React Native projects too.

npx expo install expo-image
import { Image } from 'expo-image';

type CoverProps = { url: string; blurhash: string; width: number; height: number };

export function Cover({ url, blurhash, width, height }: CoverProps) {
  return (
    <Image
      source={{ uri: url }}
      placeholder={{ blurhash }}
      contentFit="cover"
      transition={250}
      cachePolicy="memory-disk"
      recyclingKey={url}
      style={{ width, aspectRatio: width / height }}
      accessibilityLabel="Book cover"
    />
  );
}
  • placeholder={{ blurhash }} decodes the BlurHash natively and shows it until the image is ready. The prop also accepts { thumbhash } for ThumbHash and a plain image source, see the algorithm page.

  • cachePolicy is one of none, disk, memory, memory-disk. memory-disk keeps the decoded image in memory for quick re-display and the file on disk. Use disk for large lists where memory is tight.

  • recyclingKey helps in recycled list cells (FlashList and FlatList), so a recycled cell does not show the previous image.

  • contentFit replaces resizeMode (values like cover and contain), and transition cross-fades.

Prefetch the next images, and clear caches when needed:

await Image.prefetch(nextPageUrls, { cachePolicy: 'disk' });
await Image.clearDiskCache();

Choose the URL from the API’s variant list by the size in pixels (PixelRatio.getPixelSizeForLayoutSize(width)) and prefer WebP or AVIF, as in the helper on the Android page. Reference: expo-image placeholder and cachePolicy.

react-native-blurhash

react-native-blurhash renders a BlurHash with a native view, and can encode one from an image on the device.

import { Blurhash } from 'react-native-blurhash';

<Blurhash blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj" decodeWidth={32} decodeHeight={32} decodePunch={1}
          style={{ width: 160, height: 240 }} />

Use it with react-native Image or a custom image component when you do not use expo-image, which already includes placeholder support. Its last release at the baseline date was in December 2025, so check that it supports your React Native version and architecture before you add it.

react-native-fast-image

react-native-fast-image wraps SDWebImage and Glide. Its README at the baseline date (version 9.1.0, published 2026-10-06) says it works with React Native 0.65 and later, with the New Architecture through React Native’s interop layer, and that a native New Architecture component is planned for a future major version. It had a long period without updates before this revival, so check its README for the New Architecture status of your React Native version. A community fork, @d11/react-native-fast-image, adds Fabric support.

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

<FastImage
  style={{ width: 160, height: 240 }}
  source={{ uri: url, priority: FastImage.priority.normal, cache: FastImage.cacheControl.immutable }}
  resizeMode={FastImage.resizeMode.cover}
/>

For a new project, expo-image is the simpler choice. Keep FastImage where an app already depends on it.

react-native-video

react-native-video plays video through ExoPlayer on Android (Media3) and AVPlayer on iOS, so HLS plays natively on both, see Android Media3 and iOS AVFoundation.

import Video from 'react-native-video';

<Video
  source={{ uri: 'https://cdn.example.com/videos/42/master.m3u8' }}
  poster={{ source: { uri: posterUrl } }}
  paused={!playing}
  resizeMode="contain"
  style={{ width: '100%', aspectRatio: 16 / 9 }}
  onError={(e) => console.warn(e)}
/>

The API differs between major versions (version 7 moved to a player object and a useVideoPlayer hook), so follow the documentation of the version you install. Expo offers expo-video as an alternative with a similar approach, see expo-video. Create the poster as described in video covers and thumbnails.

Compressing before upload

expo-image-manipulator resizes and re-encodes images (JPEG, PNG, WebP) on the device, and libraries such as react-native-compressor compress video. See device-side compression and uploads.