the right library for every use case
Video and audio playback in React Native isn't one uniform problem: a short TikTok-style video feed, a podcast player with lock screen controls, and an on-demand video player with adaptive streaming all need different technical foundations. The choice between expo-video, react-native-video and react-native-track-player directly decides whether background audio, DRM protection and memory management work reliably.
Table of contents
- 1. Choosing the right library for the use case
- 2. A basic video player component
- 3. Adaptive streaming with HLS and DASH
- 4. Configuring background audio playback
- 5. Lock screen and control center controls
- 6. Offline playback and download caching
- 7. Picture-in-picture and DRM-protected content
- 8. Performance tuning with multiple video instances
- 9. Testing and a comparison of the libraries
- 10. Summary
- 11. FAQ
1. Choosing the right library for the use case
Video playback in React Native has changed significantly with the transition from expo-av to the separate expo-video and expo-audio packages. Google and Apple keep advancing their native player APIs, and the split Expo packages reflect that separation better than the older, monolithic expo-av, which is now marked deprecated. For Expo projects with standard requirements for video and audio playback, expo-video and expo-audio are therefore the recommended starting point.
For bare React Native projects or use cases with advanced streaming requirements, such as detailed control over bitrate switching or custom native extensions, react-native-video remains the more established choice with a larger community and more native configuration options. For a dedicated audio player use case like a podcast or music app, react-native-track-player is in turn the most specialized solution, since this library was built from the ground up for queue management, lock screen control and background playback, instead of bolting these features onto a generic video player afterward.
This three-way split isn't an academic distinction: a TikTok-style short video feed with dozens of concurrently rendered video elements poses entirely different demands on memory management than a single podcast player running permanently in the background. Picking the wrong library for the given use case leads to workarounds down the line that could have been avoided had the decision been made deliberately from the start.
2. A basic video player component
A basic video player component with expo-video consists of a video hook that provides a player state with play, pause and seek functions, combined with a custom UI overlay component for controls, since the native default UI often doesn't match the rest of the app's design. The main advantage of expo-video over the older expo-av is a noticeably more reactive API, where player state can be observed directly through React hooks instead of manually listening for status events.
For the controls themselves, a proven pattern automatically hides the control bar after a few seconds of no interaction, similar to native video app behavior, and shows it again on tapping the video area. A poster image shown during initial loading prevents an unsightly black screen and significantly improves perceived load time.
// VideoPlayerScreen.tsx - basic expo-video player with custom controls
import { useVideoPlayer, VideoView } from 'expo-video';
import { useState } from 'react';
import { Pressable, View } from 'react-native';
export function VideoPlayerScreen({ videoUrl, posterUrl }) {
const player = useVideoPlayer(videoUrl, (p) => {
p.loop = false;
});
const [showControls, setShowControls] = useState(true);
return (
<View style={{ flex: 1 }}>
<VideoView
player={player}
style={{ flex: 1 }}
contentFit="contain"
nativeControls={false}
/>
<Pressable
style={{ position: 'absolute', inset: 0 }}
onPress={() => setShowControls((v) => !v)}
>
{showControls && (
<View style={{ position: 'absolute', bottom: 20, left: 20, right: 20 }}>
{/* Custom play/pause/seek controls go here */}
</View>
)}
</Pressable>
</View>
);
}
3. Adaptive streaming with HLS and DASH
For on-demand video, adaptive bitrate streaming via HLS manifests on iOS and both HLS and DASH on Android is the standard approach for dynamically adjusting video quality to the user's available bandwidth. An HLS manifest references multiple video streams at different quality levels, between which the native player automatically switches during playback, without the app itself needing to measure bandwidth or make quality decisions.
Both expo-video and react-native-video support HLS sources directly via the manifest URL, without additional configuration needed, as long as the server delivers correct HLS segments and a valid master playlist format. For DASH streaming on Android, react-native-video additionally offers more detailed native configuration options, such as preferred starting quality or bandwidth estimation strategies, which can become relevant for enterprise video applications with high quality requirements.
4. Configuring background audio playback
For audio playback to keep running when the app moves to the background or the screen locks, the audio session category must be explicitly set to playback on iOS, instead of the default category that automatically mutes playback on lock. On Android, continuous background playback requires a foreground service with a visible notification, since the operating system otherwise terminates app processes without a visible notification hint shortly after they move to the background.
This difference between platforms is often underestimated: while iOS allows background audio through a simple configuration setting, Android demands an explicit, user-visible notification for the entire duration of playback. react-native-track-player already fully encapsulates this platform-specific complexity and provides a ready-made notification layout for it, while with plain expo-video or react-native-video the foreground service configuration has to be retrofitted manually.
{
"expo": {
"plugins": [
[
"expo-audio",
{
"microphonePermission": false
}
]
],
"ios": {
"infoPlist": {
"UIBackgroundModes": ["audio"]
}
},
"android": {
"permissions": ["FOREGROUND_SERVICE", "FOREGROUND_SERVICE_MEDIA_PLAYBACK"]
}
}
}
5. Lock screen and control center controls
A podcast or music player user expects to be able to pause, skip to the next track, or change playback position directly from the lock screen or control center, without opening the app. react-native-track-player provides a ready-made "Now Playing" integration for this, automatically passing title, artist and cover art to the operating system's native media session API and reporting remote control events, such as a button press on a Bluetooth headset, directly back to the app.
With more generic video libraries like expo-video or react-native-video, this integration for a dedicated audio use case largely has to be rebuilt manually via native modules, which considerably increases the additional implementation effort for a music or podcast project compared to react-native-track-player. For a video-centric project with occasional background audio, the simpler configuration usually suffices, though.
6. Offline playback and download caching
For offline playback, video material has to be downloaded in advance and cached locally, which requires both storage space management and a strategy for cleaning up old, no-longer-needed downloads. A typical implementation downloads segments via a background download task, tracks progress through a progress callback, and marks completed downloads as available offline in a local database.
The operating system's app storage limit plays an important role here: if too much video material is cached at once, iOS or Android can automatically clean up app data under low device storage, without explicitly informing the app about it. A robust implementation therefore checks on every app start whether cached files are actually still present, instead of blindly relying on the last known download status.
7. Picture-in-picture and DRM-protected content
Picture-in-picture lets users keep watching a video in a small, floating window while switching to another app, a feature both iOS and Android support natively, but implemented to differing degrees per library. react-native-video already offers a built-in prop to enable it, while support in expo-video can vary by SDK version and should be checked against the current documentation before production use.
For premium video content with license protection, DRM via Widevine on Android and FairPlay on iOS is necessary, requiring additional server infrastructure for license issuance as well as native configuration of the player for the respective DRM key server. react-native-video offers more mature configuration options for this than expo-video, which is why projects with serious DRM requirements, such as streaming services with licensed content, usually reach for react-native-video or an even more specialized native integration in practice.
// iOS reference: configuring an AVAudioSession for background playback
import AVFoundation
func configureBackgroundAudioSession() throws {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playback, mode: .default, options: [])
try session.setActive(true)
}
8. Performance tuning with multiple video instances
A common performance mistake in list-style video feeds is that the parent component re-renders on every scroll event and accidentally recreates the video player along with it, causing a visible stutter and a reload. The player itself should be held via useMemo or a stable reference outside of the frequently re-rendering parent, to avoid this unwanted behavior.
In a TikTok-style short video feed, all visible and invisible video elements should also never be kept concurrently active in memory. A proven pattern limits active player instances to the currently visible element plus one element before and after it, while elements further away in the list only show the poster image and only reactivate their player once they scroll back into the visible area.
9. Testing and a comparison of the libraries
Playback should be tested under various network conditions, especially with throttled bandwidth via Xcode's network condition simulator or the Android emulator's network profile, to ensure that adaptive streaming actually switches down to lower quality levels instead of completely stalling on a poor connection. Testing app switching during ongoing playback is equally important, to verify background audio configuration and lock screen controls.
The following overview summarizes which library is the most suitable choice for which use case.
| Criterion | expo-video / expo-audio | react-native-video | react-native-track-player |
|---|---|---|---|
| Good use case fit | Standard video/audio in Expo apps | On-demand VOD, advanced streaming | Podcast and music players |
| Background audio | Manually configurable | Manually configurable | Built in, ready-made solution |
| DRM support | Limited | Mature, Widevine/FairPlay | Not the library's focus |
| Streaming protocols | HLS | HLS and DASH | HLS, primarily audio-focused |
| Maintenance status | Active, official Expo team | Active, large community | Active, specialized niche |
Mironsoft
React Native development, streaming integration and media player architecture
Want video and audio playback integrated reliably in your app?
We pick the right player library for your use case, implement adaptive streaming, background audio and lock screen controls, and tune performance for multiple concurrent video instances.
Player architecture
Library selection and custom UI matching your streaming use case
Background audio
Lock screen controls, foreground service and Now Playing integration
Performance tuning
Memory management in video feeds and stable player references
10. Summary
Video and audio playback in React Native requires a different technical foundation depending on use case: expo-video and expo-audio cover standard requirements in Expo projects, react-native-video offers more mature DRM and streaming configuration for on-demand video, and react-native-track-player is the most specialized solution for dedicated podcast and music players with lock screen controls.
Background audio configuration differs fundamentally between iOS and Android, adaptive HLS and DASH streaming automatically adjusts video quality to bandwidth, and performance tuning for multiple concurrent video instances prevents memory issues in feed-style layouts. Choosing the right library early in the project, instead of switching between them afterward, saves considerable implementation effort over the entire project lifetime.
React Native Video and Audio Playback — Key takeaways
Library choice
expo-video for standard cases, react-native-video for DRM/streaming, react-native-track-player for audio players.
Background audio
iOS via the playback audio session category, Android via a foreground service with a visible notification.
Adaptive streaming
HLS manifests automatically adjust video quality to available bandwidth.
Performance
Limit active player instances in feeds, keep stable references via useMemo.