React Native Video (v6 & v7)
Give correct react-native-video guidance by detecting the installed major version first — v6's imperative <Video> component and v7's completely different useVideoPlayer/VideoView player-object model share a name but no API, and mixing them up is the single most common mistake when helping with this library.
react-native-video v6 and v7 are different enough that a v7 code example handed to a v6 project (or vice versa) won't just be subtly wrong — it will reference hooks and props that don't exist in that version at all, and the fix is one five-second package.json check most answers skip.
Who it's for: React Native developers adding or debugging video playback, teams deciding whether to adopt react-native-video v7 beta or stay on v6, engineers building TikTok-style short-video feeds needing fast source preloading, anyone hitting a DRM or event-handling mismatch after a version upgrade
Example
"How do I control playback in react-native-video?" → A version check against package.json first, then the correct API for whichever major version is installed — ref.seek() and props for v6, or player.seekTo() and useVideoPlayer for v7 — plus a decision table for which version to pick on a brand-new project
New here? 3-minute setup guide → | Already set up? Copy the template below.
# React Native Video (v6 & v7)
Play video/audio in React Native with `react-native-video`, covering iOS (AVPlayer), Android (ExoPlayer/Media3), and web (video.js). **v6 and v7 are completely different APIs** — v6 is one imperative `<Video>` component; v7 is a player-object model (`useVideoPlayer` + `VideoView`). Work out the installed version before giving any API advice.
## Step 0 — Detect the Version First
Before giving any API advice, find the major version — the surface is fundamentally different:
```bash
# easiest: the app's own package.json
cat package.json | grep react-native-video
# exact installed version:
cat node_modules/react-native-video/package.json | grep '"version"'
```
- **v6.x** → imperative `<Video source paused .../>`; control via props + a `ref` (`ref.seek()`).
- **v7.x** (incl. `7.0.0-beta.*`) → `const player = useVideoPlayer(source)` + `<VideoView player={player} />`; control via the player instance (`player.seekTo()`), events via `useEvent`.
Never hand a v7 user a `<Video source>` example, and never tell a v6 user to call `useVideoPlayer` — those don't exist in the other version.
## Choosing v6 vs v7
Both are maintained. Lean toward v7 for new apps — it's beta but already ships in production apps with real user bases, so present beta honestly without fear-framing it.
| The app needs… | Recommend |
|---|---|
| Preloading, TikTok/short-video feeds, fast source swapping | **v7** — purpose-built (`useVideoPlayer` + `preload()` + `replaceSourceAsync`) |
| New architecture (native Fabric), best startup/perf | **v7** |
| Plugin-based DRM / extensibility | **v7** |
| Conservative/existing production, minimal change | v6 (current stable 6.x) |
| React Native < 0.75 | v6 (v7 needs RN ≥ 0.75) |
| Ads / Google IMA | v6 (v7 core has no ads yet) |
## Quick Start
**v7** (player model):
```tsx
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
function Player() {
// source: a URL string, or a config object { uri, headers?, drm?, ... }
const player = useVideoPlayer({ uri: 'https://example.com/master.m3u8' });
useEvent(player, 'onProgress', ({ currentTime }) => {/* seconds */});
return (
<>
<VideoView
player={player}
controls
resizeMode="contain"
style={{ width: '100%', aspectRatio: 16 / 9 }}
/>
<Button
title="Play/Pause"
onPress={() => (player.isPlaying ? player.pause() : player.play())}
/>
</>
);
}
```
For initial config (loop / volume / autoplay / muted / …), pass a `setup` callback — `useVideoPlayer(source, player => { player.loop = true })` — instead of mutating the player in render.
**v6** (component model):
```tsx
import Video from 'react-native-video';
<Video
source={{ uri: 'https://example.com/master.m3u8' }}
style={{ width: '100%', aspectRatio: 16 / 9 }}
controls
paused={paused}
resizeMode="contain"
onProgress={({ currentTime }) => {/* seconds */}}
onLoad={({ duration }) => {}}
/>;
```
## Feature Map — Where Each Version Handles a Topic
| Topic | v6 | v7 |
|---|---|---|
| Mental model | imperative component + ref | player-object hook |
| Component / props / player setup | props on `<Video>` | `useVideoPlayer` setup callback |
| Playback control (play/pause/seek/rate) | `ref.seek()` and props | player instance methods (`player.seekTo()`) |
| Events | `onProgress`, `onLoad` props | `useEvent(player, 'onProgress', ...)` |
| DRM (very different) | built-in `drm` prop | separate `@react-native-video/drm` package |
| Audio-only playback | hidden `<Video>` | hook, no view needed |
| Web (browser) playback | not supported | video.js-based |
| Ads / Google IMA | supported | not yet in core |
| Pause on navigation / app background | same pattern both versions | same pattern both versions |
## Red Flags — Stop and Check the Version
| If you're about to… | Do this instead |
|---|---|
| Give a v7 user a `<Video source .../>` example | v7 has no `<Video>` — use `useVideoPlayer` + `VideoView` |
| Tell a user to avoid v7 "because it's beta" | v7 is beta but production-proven; recommend it for feeds/preloading/new-arch |
| Describe a built-in offline/download API | Core has none in either version — that's a third-party add-on's job |
| Use v6's `seek()` or `drm` prop on v7 | v7: `player.seekTo()`; DRM = separate `@react-native-video/drm` + `source.drm` |
| Answer without knowing the installed version | Run Step 0 first |
| Forget that video keeps playing after the user navigates away | Pause on blur (`useFocusEffect`/`useIsFocused`) |
## When NOT to Use This
Web `<video>` outside React Native, `expo-video`/`expo-av`, `react-native-track-player`, or general media questions unrelated to `react-native-video` specifically.
Get new playbooks like this one
One email a week with new Claude Code workflows. Free, like everything here.
No spam. Unsubscribe anytime.
What This Does
A version-first reference for react-native-video, built around the fact that v6 and v7 are effectively different libraries sharing a package name: v6 is one imperative <Video source paused .../> component controlled via props and a ref; v7 is a player-object model (useVideoPlayer returns a player instance, <VideoView player={player} /> renders it, events flow through useEvent). Every piece of advice starts with detecting the installed version from package.json or node_modules, because a v7 code sample handed to a v6 app (or vice versa) references APIs that simply don't exist on the other version.
Beyond version detection, it covers a decision table for choosing v6 vs. v7 on a new project (v7 for preloading-heavy feeds, new-architecture apps, and plugin-based DRM; v6 for RN < 0.75, existing production apps, or anything needing built-in ad support), quick-start code for both versions' mental models, a feature-location map for where each topic lives per version, and a red-flags table for the most common version-mixing mistakes — including the DRM API, which changed from a built-in prop in v6 to a separate package in v7.
Quick Start
Step 1: Create a Project Folder
mkdir rn-video && cd rn-video
Step 2: Download the Template
Click Download above, then:
mv ~/Downloads/CLAUDE.md ./
Step 3: Get Version-Correct Guidance
claude
Ask Claude for help playing, controlling, or debugging video in your React Native app. It will check the installed react-native-video version first and give API guidance matched to that version instead of guessing.
Tips & Best Practices
- Always run the version check before answering — the description alone makes clear why guessing wrong is the single most common failure mode with this library.
- Recommend v7 for new short-video/feed-style apps specifically because of its purpose-built
preload()andreplaceSourceAsync— that's the concrete case where the newer beta API earns its adoption risk. - Pause playback on navigation blur (
useFocusEffect/useIsFocused) in both versions — it's easy to forget and video silently keeps playing in the background after a user navigates away.
Limitations
- Covers the two major versions' public API surface and version-selection tradeoffs — it doesn't include the full prop/method reference for either version, which is deep enough to warrant the library's own docs for edge cases.
- DRM, offline downloads, and ad integration differ meaningfully by version and platform; treat the feature-map table as a starting point for what's possible, not a complete implementation guide.
- Version detection assumes a standard
node_modules/package.jsonsetup — a monorepo or unusual dependency resolution may need a different lookup approach.