react-native-video is the foundational, low-level video engine for React Native, providing direct access to native iOS (AVPlayer) and Android (ExoPlayer) capabilities. It offers maximum flexibility but requires developers to build their own UI controls and state management. react-native-video-controls is a wrapper component that layers a customizable set of playback controls (play/pause, seek, volume) on top of react-native-video, solving the UI problem while keeping the core engine exposed. react-native-video-player is a higher-level, opinionated solution that bundles the engine and controls into a single, polished component with built-in fullscreen handling and default styling, aiming for rapid implementation with less configuration.
Implementing video in React Native is one of the most common yet tricky challenges. You have three main paths: building from the ground up with react-native-video, using a control-layer wrapper like react-native-video-controls, or grabbing a fully baked solution like react-native-video-player. Each choice trades off flexibility against development speed. Let's dig into how they actually work in production.
The fundamental difference lies in what responsibility each package takes on. react-native-video is purely the engine. It renders the native video view but leaves the "play" button, the progress bar, and the fullscreen logic entirely up to you.
react-native-video gives you the raw native component. You must manage the paused state, the current currentTime, and the UI overlay yourself.
// react-native-video: You own the state and the UI
import Video from 'react-native-video';
import { View, TouchableOpacity, Text } from 'react-native';
const CustomPlayer = () => {
const [paused, setPaused] = useState(false);
const videoRef = useRef(null);
return (
<View style={{ flex: 1 }}>
<Video
ref={videoRef}
source={{ uri: 'https://example.com/video.mp4' }}
paused={paused}
onProgress={(data) => console.log('Progress:', data.currentTime)}
style={{ width: '100%', height: 200 }}
/>
{/* You must build this button yourself */}
<TouchableOpacity onPress={() => setPaused(!paused)}>
<Text>{paused ? 'Play' : 'Pause'}</Text>
</TouchableOpacity>
</View>
);
};
react-native-video-controls wraps the engine. It injects a default control layer but exposes the underlying Video reference so you can still talk to the engine directly if needed.
// react-native-video-controls: Built-in controls, exposed engine
import VideoPlayer from 'react-native-video-controls';
import { useRef } from 'react';
const WrappedPlayer = () => {
const playerRef = useRef(null);
return (
<VideoPlayer
ref={playerRef}
source={{ uri: 'https://example.com/video.mp4' }}
// You can still access the underlying video node
onPaused={(data) => console.log('Player paused', data)}
// But the Play/Pause UI is handled internally
disableFullscreen={false}
/>
);
};
react-native-video-player encapsulates everything. It attempts to hide the complexity of the engine entirely, offering a simplified prop surface area focused on "just playing video."
// react-native-video-player: High-level abstraction
import VideoPlayer from 'react-native-video-player';
const SimplePlayer = () => {
return (
<VideoPlayer
video={{ uri: 'https://example.com/video.mp4' }}
// Very few props available; mostly styling overrides
autoplay={true}
// Fullscreen and controls are managed internally with little override options
/>
);
};
When your design team hands you a Figma file that doesn't look like the default iOS or Android player, your choice of library dictates how much pain you will feel.
react-native-video offers infinite customization because you build the UI from standard React Native views. You can animate icons, create gesture-based scrubbing, or overlay complex graphics.
// react-native-video: Total control over UI elements
<Video source={source} paused={paused} />
<View style={styles.customOverlay}>
<CustomAnimatedPlayButton isActive={!paused} />
<CustomScrubber
progress={currentTime}
onSeek={(time) => videoRef.current.seek(time)}
/>
<LogoOverlay style={{ opacity: 0.5 }} />
</View>
react-native-video-controls allows you to swap out specific components (like the play button or seek bar) via props, but you are still working within its layout structure.
// react-native-video-controls: Swap components via props
<VideoPlayer
source={source}
// Pass your own custom component for the play button
customPlayIcon={<MyBrandPlayIcon />}
// Pass your own seek bar component
customSlider={<MyCustomSlider />}
// But the container layout is largely dictated by the library
controlTimeout={2000}
/>
react-native-video-player provides limited styling hooks. You can change colors and some dimensions, but radically changing the layout (e.g., moving controls to the side for a landscape dashboard) is often difficult or impossible without forking the library.
// react-native-video-player: Limited style props
<VideoPlayer
source={source}
// Only basic style overrides supported
style={{ borderRadius: 10 }}
videoStyle={{ resizeMode: 'cover' }}
// Cannot easily replace the internal control bar structure
/>
Handling fullscreen transitions smoothly on both iOS and Android is notoriously difficult due to differences in how native views handle hierarchy changes.
react-native-video requires you to manually handle the fullscreen logic. You must listen to events and use the Native Modules or specific props to trigger the transition, giving you precise control over when and how it happens.
// react-native-video: Manual fullscreen management
<Video
source={source}
// Trigger fullscreen programmatically
onFullscreenPlayerWillPresent={() => console.log('Going full')}
// You must manage the state that drives this
fullscreen={isFullscreen}
// Or use the native control if enabled
controls={true}
/>
react-native-video-controls includes built-in fullscreen handling. It manages the state transition for you, which works well for standard apps but can sometimes conflict if you try to implement a custom navigation header during fullscreen.
// react-native-video-controls: Automated fullscreen
<VideoPlayer
source={source}
// Built-in toggle button included in controls
disableFullscreen={false}
// Callbacks let you react to changes, but logic is internal
onEnterFullscreen={() => console.log('Entered full')}
/>
react-native-video-player handles fullscreen automatically and aggressively. It often forces its own navigation stack or modal presentation, which can feel disjointed if your app uses a custom navigation library like React Navigation with specific transition animations.
// react-native-video-player: Opinionated fullscreen
<VideoPlayer
source={source}
// Fullscreen behavior is baked in and hard to decouple
// from the component's internal state machine
fullscreen={true}
/>
A critical architectural consideration is the long-term viability of the package.
react-native-video is the industry standard and is actively maintained. It receives regular updates to support new iOS and Android OS versions, new codec formats, and bug fixes. It is the safest bet for long-term projects.
react-native-video-controls relies directly on react-native-video. While it has seen periods of slower activity, it generally tracks the core library's updates. However, because it adds a layer of abstraction, there is a risk of breakage if the core API changes significantly and the wrapper isn't updated immediately.
react-native-video-player has historically suffered from long periods of inactivity and unresolved issues regarding newer React Native versions. Warning: Before choosing this package for a new production app, verify its current maintenance status on npm and GitHub. If the repository shows no recent commits addressing the latest React Native version, do not use it. The risk of being stuck with a broken player during an OS upgrade is too high. In many cases, migrating to react-native-video-controls is a safer architectural decision.
You need vertical videos that autoplay, loop, and respond to complex swipe gestures with custom overlays (likes, comments) drawn directly on the video surface.
react-native-video// Custom implementation for swipe-to-next
<Video
ref={ref}
source={source}
repeat={true}
paused={!isFocused} // Logic based on viewability
// No default controls interfering with swipe gestures
/>
You need a reliable player for course content with standard play/pause/seek, but it must match the company's branding (custom colors, specific font icons).
react-native-video-controls// Branded training player
<VideoPlayer
source={courseVideo}
customPlayIcon={<CompanyIcon name="play" />}
seekColor={companyColors.primary}
// Standard behavior, custom look
/>
You need to quickly embed a security camera feed or a recorded webinar in an internal tool used only by employees. Design doesn't matter; speed does.
react-native-video-player (if maintained) or react-native-video-controlsreact-native-video-player is unmaintained, react-native-video-controls is the next fastest option with better long-term safety.// Quick embed
<VideoPlayer source={streamUrl} />
| Feature | react-native-video | react-native-video-controls | react-native-video-player |
|---|---|---|---|
| Core Role | Native Engine | Control Layer Wrapper | All-in-One Component |
| UI Controls | β None (Build your own) | β Customizable Defaults | β Fixed Defaults |
| Customization | βββββ (Unlimited) | βββ (Component Swapping) | β (Style Props Only) |
| Fullscreen | π§ Manual / Native API | π€ Automated | π€ Automated (Opinionated) |
| Maintenance Risk | π’ Low (Active) | π‘ Medium (Dependency) | π΄ High (Check Status) |
| Dev Effort | High | Medium | Low |
If you are building a product where video is a core feature (like a streaming service, social app, or education platform), start with react-native-video. The initial cost of building your own controls pays off immediately when you need to implement unique interactions or fix a specific native bug that a wrapper might obscure.
For standard content apps where video is important but not the entire product identity, react-native-video-controls is the pragmatic sweet spot. It respects your time while keeping the door open for customization.
Treat react-native-video-player with skepticism. Only use it for throwaway prototypes or internal tools where you can afford to rewrite the component if the library breaks in six months. In professional architecture, relying on an unmaintained wrapper around a rapidly evolving native layer is a technical debt trap.
Choose react-native-video if you are building a custom video experience where the UI design system is strict or unique, such as a TikTok-style feed, a custom educational platform, or a broadcast application. This package is essential when you need direct access to low-level events (like precise buffer progress or native fullscreen callbacks) and want to avoid the overhead of stripping out unwanted features from a pre-built player. Be prepared to invest significant engineering time in building and maintaining your own control layer and state logic.
Select react-native-video-controls when you need a standard set of playback controls quickly but still require the flexibility to customize the look and feel to match your brand. This is the ideal middle ground for most commercial apps (like news readers or standard content portals) where the default control behavior is acceptable, but the default styling is not. It saves you from writing boilerplate control logic while allowing you to pass custom components for buttons and sliders.
Opt for react-native-video-player for internal tools, prototypes, MVPs, or applications where a standard, functional video player is needed immediately with minimal code. This package is best when you do not have specific design requirements for the player UI and are willing to accept its default behavior and styling constraints. Avoid this for complex, consumer-facing products where deep customization of the playback experience or specific native fullscreen behaviors are critical requirements.
The most battle-tested open-source video player component for React Native with support for DRM, offline playback, HLS/DASH streaming, and more.
| Version | State | Architecture |
|---|---|---|
| v5 and lower | β End-of-life Commercial Support Available | Old Architecture |
| v6 | π Maintained (community + TWG) | Old + New (Interop Layer) |
| v7 | π Active Development | Old + New (Full Support) |
react-native-video v7 introduces full support for the new React Native architecture, unlocking better performance, improved consistency, and modern native modules.
# Install dependencies
yarn add react-native-video
# Install pods
cd ios && pod install
import Video from 'react-native-video';
export default () => (
<Video
source={{ uri: 'https://www.w3schools.com/html/mov_bbb.mp4' }}
style={{ width: '100%', aspectRatio: 16 / 9 }}
controls
/>
);
If you're building a video-first app and need to download HLS streams for offline playback, you're in the right place.
This SDK supports:
v6 and v7 versionsπ Start Free Trial on the SDK Platform β
If you're building a video-first app and need to upload large video files reliably in the background, you're in the right place.
This SDK supports:
Whether you're building social media apps, content platforms, or enterprise solutions, our Background Upload SDK ensures your users can upload videos seamlessly without interruption.
Contact us to learn more about integrating background video uploads into your React Native application.
π Contact us at hi@thewidlarzgroup.com
Write your own plugins to extend library logic, attach analytics or add custom workflows - without forking the core SDK.
β Plugin documentation
| Offering | Description |
|---|---|
| Professional Support Packages | Priority bug-fixes, guaranteed SLAs, roadmap influence |
| Issue Booster | Fast-track urgent fixes with a payβperβissue model |
| Offline Video SDK | Plugβandβplay secure download solution for iOS & Android |
| Background Upload SDK | Reliable background upload solution for iOS & Android |
| Integration Support | Handsβon help integrating video, DRM & offline into your app |
| Free DRM Token Generator | Generate Widevine / FairPlay tokens for testing |
| Ready Boilerplates | Ready-to-use apps with offline HLS/DASH DRM, video frame scrubbing, TikTok-style video feed, background uploads, Skia-based frame processor (R&D phase), and more |
| React Native Video Upgrade Guide | Common upgrade pitfalls & how to solve them |
See how TWG helped Learnn ship a worldβclass player in record time - case study.
Contact us at hi@thewidlarzgroup.com
π½ React Summit US β How TWG helped Learnn boost video performance on React Native.
Watch the talk Β»
𧨠v7 deep dive β Why weβre building v7 with Nitro Modules Watch on X Β»
π οΈ Well-maintained open-source library - What does it truly mean? - Bart's talk for React Native Warsaw Watch here Β»
πΊ βOver the Topβ Panel - Building Streaming Apps for Mobile, Web, and Smart TVs - Bart giving his insights on the industry Watch here Β»