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: the recommended default
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. -
cachePolicyis one ofnone,disk,memory,memory-disk.memory-diskkeeps the decoded image in memory for quick re-display and the file on disk. Usediskfor large lists where memory is tight. -
recyclingKeyhelps in recycled list cells (FlashList and FlatList), so a recycled cell does not show the previous image. -
contentFitreplacesresizeMode(values likecoverandcontain), andtransitioncross-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.