expo-av, react-native-sound, and react-native-track-player are the primary libraries for handling audio in React Native, but they solve distinctly different problems. expo-av is a comprehensive, managed module within the Expo ecosystem that handles both audio and video, offering a balanced API for playback, recording, and streaming without native code configuration. react-native-sound is a lightweight, community-maintained library focused strictly on playing short sound effects and UI feedback with minimal setup, though it lacks advanced streaming or background capabilities. react-native-track-player is a specialized, robust solution designed specifically for music players and podcasts, providing full support for background playback, lock screen controls, and remote handling via native media sessions.
Choosing the right audio library in React Native is not just about picking a feature list; it is about matching the library's architectural model to your app's lifecycle requirements. expo-av, react-native-sound, and react-native-track-player represent three distinct approaches: the all-in-one managed solution, the lightweight effect player, and the dedicated background service engine. Let's break down how they handle real-world engineering challenges.
The barrier to entry varies significantly depending on your project structure and how much native control you need.
expo-av is built for the Managed Workflow.
// expo-av: Import and use directly
import { Audio } from 'expo-av';
async function playSound() {
const { sound } = await Audio.Sound.createAsync(
require('./assets/hello.mp3')
);
await sound.playAsync();
}
react-native-sound requires manual linking or CocoaPods/Gradle setup.
// react-native-sound: Requires native setup
import Sound from 'react-native-sound';
Sound.setCategory('Playback');
const whoosh = new Sound('whoosh.mp3', Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('failed to load the sound', error);
return;
}
whoosh.play();
});
react-native-track-player demands the most setup.
// react-native-track-player: Setup in index.js
import TrackPlayer from 'react-native-track-player';
export async function PlaybackService() {
TrackPlayer.addEventListener('remote-play', () => TrackPlayer.play());
TrackPlayer.addEventListener('remote-pause', () => TrackPlayer.pause());
}
TrackPlayer.registerPlaybackService(() => PlaybackService);
How the library manages the audio engine dictates what kind of content you can play.
expo-av uses a high-level Sound object that manages its own lifecycle.
// expo-av: Looping a sound
const { sound } = await Audio.Sound.createAsync(
{ uri: 'https://example.com/stream.mp3' },
{ isLooping: true }
);
await sound.playAsync();
react-native-sound loads the entire file into memory or streams simply.
// react-native-sound: Simple playback
const music = new Sound('music.mp3', Sound.MAIN_BUNDLE);
music.play((success) => {
if (success) {
console.log('successfully finished playing');
} else {
console.log('playback failed due to audio decoding errors');
}
});
react-native-track-player utilizes a native background queue.
// react-native-track-player: Queue management
import TrackPlayer from 'react-native-track-player';
await TrackPlayer.setupPlayer();
await TrackPlayer.add({
id: 'track1',
url: 'https://example.com/song.mp3',
title: 'My Song',
artist: 'Artist Name'
});
await TrackPlayer.play();
This is the most critical differentiator for music and podcast apps.
expo-av has limited background support out of the box.
app.json and use a Development Client.// expo-av: Limited native control exposure
// No direct API to update lock screen metadata like 'Next' button handlers
// without additional native modules or ejecting.
await sound.setStatusAsync({ shouldPlay: true });
react-native-sound does not support background playback.
// react-native-sound: No background capability
// If the user presses the home button, audio stops.
// No code exists to enable lock screen controls.
react-native-track-player is built specifically for this.
PlaybackService runs in a separate thread, surviving app suspension.// react-native-track-player: Updating metadata and capabilities
await TrackPlayer.updateOptions({
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_SKIP_TO_NEXT,
],
compactCapabilities: [TrackPlayer.CAPABILITY_PLAY, TrackPlayer.CAPABILITY_PAUSE],
});
await TrackPlayer.updateMetadata({
title: 'New Song',
artist: 'New Artist',
// Updates lock screen and control center immediately
});
Some apps need to capture audio, not just play it.
expo-av provides a complete Recording API.
// expo-av: Recording audio
const { recording } = await Audio.Recording.createAsync(
Audio.RecordingOptionsPresets.HIGH_QUALITY
);
// Stop and get file URI
await recording.stopAndUnloadAsync();
const uri = recording.getURI();
react-native-sound has no recording features.
react-native-audio-recorder-player) to add this.// react-native-sound: No recording API
// Cannot record audio with this library.
react-native-track-player does not support recording.
// react-native-track-player: No recording API
// Focused purely on playback queue management.
Despite their differences, these libraries share some common React Native patterns.
All three allow you to adjust volume programmatically, though the scope differs.
// expo-av
await sound.setVolumeAsync(0.5);
// react-native-sound
whoosh.setVolume(0.5);
// react-native-track-player
await TrackPlayer.setVolume(0.5);
Each library provides a way to know when a sound finishes.
// expo-av
sound.setOnPlaybackStatusUpdate((status) => {
if (status.isLoaded && status.didJustFinish) { /* ... */ }
});
// react-native-sound
whoosh.play((success) => { if(!success) { /* finished or error */ } });
// react-native-track-player
TrackPlayer.addEventListener('playback-track-changed', (data) => { /* ... */ });
All support loading from local bundles and remote URLs.
// All three support this pattern conceptually
// expo-av: require('./local.mp3') or { uri: 'https://...' }
// react-native-sound: new Sound('file.mp3', Sound.MAIN_BUNDLE)
// react-native-track-player: url: 'https://...' or require('./local.mp3')
| Feature | expo-av | react-native-sound | react-native-track-player |
|---|---|---|---|
| Primary Use Case | General purpose (Video + Audio) | UI Sound Effects | Music Players / Podcasts |
| Background Playback | Limited (Requires Config Client) | โ Not Supported | โ Fully Supported |
| Lock Screen Controls | โ Manual/Complex | โ Not Supported | โ Native Integration |
| Recording | โ Built-in | โ None | โ None |
| Expo Go Support | โ Yes | โ No | โ No |
| Complexity | Medium | Low | High |
expo-av is the pragmatic choice for most standard apps.
If you need to record voice notes, play video, or handle simple audio within an Expo project, this is your default. It balances power with ease of use, keeping you in the managed workflow until you absolutely need more.
react-native-sound is the specialist for micro-interactions.
Use it when you need a button click to feel crisp without the overhead of a full audio engine. It is perfect for games or interactive UIs where latency matters more than features. If you try to build a music player with this, you will fight the architecture at every step.
react-native-track-player is the heavy lifter for media apps.
If your app's core value is audio content (music, audiobooks, radio), this is the only professional choice. The initial setup cost is higher, but it saves you from rebuilding native background services and media session handlers yourself. It ensures your app behaves like a first-class citizen on iOS and Android lock screens.
Final Thought: Don't over-engineer a simple sound effect with react-native-track-player, and don't under-engineer a music player with react-native-sound. Match the tool to the lifecycle requirements of your audio.
Choose expo-av if you are building within the Expo Managed Workflow or need a single library to handle both audio playback/recording and video. It is the best fit for applications requiring voice memos, video chats, or mixed media where avoiding custom native code is a priority. However, be aware that advanced background audio features may require ejecting to the Development Client or configuring specific capabilities manually.
Choose react-native-sound if your needs are limited to playing short, local sound effects like button clicks, notifications, or game SFX. It is ideal for projects where you want a tiny footprint and simple fire-and-forget playback without the complexity of streaming or background services. Do not use this for music players, long-form content, or apps requiring lock screen controls, as it lacks these architectural features.
Choose react-native-track-player if you are building a music player, podcast app, or any service requiring continuous background audio and lock screen controls. It is the only choice among the three that fully implements native Media Session APIs, allowing users to control playback from the system UI, car displays, and smartwatches. Be prepared for a more complex setup involving native configuration files and a separate JavaScript service thread.