Edit the Blog Post Header component above this, then place your content here, then fill out the Related Articles section below, if possible. You should have at least one related article and ideally, all three.
Feel free to add supplementary content to the sidebar at right, but please retain the Twitter component (it can live at the bottom of your added content).
This text component can be edited or deleted as necessary.
Related articles only have an image (the squarer version of the banner) and a title. This text can be deleted. Place 1-3 related articles.
“To share, or not to share, that is the question." - Shakespeare, if he'd been a React Native developer"
If you build apps with React Native, you've probably asked yourself this ☝️. You've got navigation, state management, business logic, UI components, most of it is the same, and is probably using the same libraries, regardless of whether you're targeting Android TV, Apple TV, or Fire TV. So why maintain separate codebases?
With Vega OS, we had a chance to get this right from the start. Rather than shipping another platform that locks you into a single target, one of our goals was to make it easy to build for multiple TV platforms at the same time. Depending on your app's architecture, you can realistically share 70-85% of your codebase across TV operating systems. In this blog post, we will walk you through how it works and helps you figure out what 'to share or not to share'.
Ready to start?
We've published several projects on GitHub. You can pick the one that fits your workflow and start your journey or read on and we will walk through the workspace setup, some of the tooling that makes it all work and what code you can share today (and what you shouldn't).
👋 Multi-TV Hello World - starter template
📺 React Native Multi-TV App Sample – production reference app
🤖 Vega Multi-TV Migration agent skill - AI assisted migration using an Agent Skill
So what does sharing code across TV platforms look like in practice? We want a setup where the shared code lives in one place and the OS specific features (video playback, native integrations, platform quirks) stay isolated.
To implement this approach, we need to refactor the Vega project into a monorepo using Yarn v4 workspaces. On the Vega side, you keep using the Vega SDK as is. For the other platforms, we use Expo TV, which gives you Android TV, Apple TV, and Web support out of the box with a single Expo project. You split things into three workspaces:
A root package.json coordinates builds across these sub projects. Each workspace has its own dependencies and build configuration, but they share common code through workspace imports.
The key rule to remember is OS packages import from shared but shared never imports from OS packages.
Note: By default, the Vega SDK works with npm, but this monorepo approach uses Yarn v4 workspaces. Ensure you use Yarn commands throughout (yarn install, yarn workspace, etc.) to avoid package manager conflicts.
While the workspace structure establishes a solid foundation, two additional tools are essential to enable the code sharing.
The first is VMRP (Vega Module Resolver Preset). Your shared code uses standard React Native imports like react-native-gesture-handler or react-native-reanimated, but Vega has its own ported versions of these libraries. VMRP is a Babel preset that automatically swaps those imports for their Vega equivalents at build time, so your shared code stays clean and portable.
You configure it in your Vega package's babel.config.js:
With this in place, from 'react-native-gesture-handler' in your shared code automatically resolves to @amazon-devices/react-native-gesture-handler when building for Vega. No conditional imports, no platform checks.
The second is Vega Studio's monorepo support. It automatically detects your workspace layout and imports the Vega sub packages automatically, when you open your project.
Enable it in Settings > Vega > Features: Monorepo, and it handles package discovery, workspace synchronisation, and build task coordination for you.
Not all code belongs in packages/shared/. Some things work identically across platforms, some need OS-specific implementations, and some sit in between. Here's how to think about what goes where.
This is the easiest win and where you get the most reuse. Your API calls, Redux/Zustand stores, data transformations, validation logic, formatting utilities usually don't have any OS specific dependencies. As a rule of thumb, if it doesn't touch a native API or render anything to screen, it belongs in packages/shared/.
The Multi-TV App Sample demonstrates this with its dynamic content loading. The catalog API client, data transforms, and type definitions all live in the shared package and every platform consumes the same data layer.
Most of your UI components are shareable too. Buttons, cards, lists, layouts, modals, grid views are usually standard React Native that works across platforms without changes.
Where it gets interesting is platform specific styling. React Native's file extension resolution handles this cleanly. Write your base component as Banner.tsx, then add platform specific extentions Banner.kepler.tsx and Metro picks the right file at build time. Not that this relies on your Metro config being set up for monorepo resolution; both the Hello World and Multi-TV App Sample repos include this configuration.
The Hello World repo shows this pattern with its HeaderLogo component, which loads different platform logos using .kepler.tsx, .android.tsx, .ios.tsx, and .web.tsx variants.
You can also use Platform.select() for smaller differences that don't warrant separate files.
There are two types of navigation patterns in TV apps:
TV apps need to look right across different screen sizes and display densities. The pattern here is the same as with the UI: share the design system (tokens, spacing, typography scales) and use platform-specific files or Platform.select() where individual platforms need adjustments. For production apps, consider building out a proper theme layer with responsive layouts rather than relying on simple scaling alone.
The Hello World repo includes scaling utilities that normalise dimensions across TV displays based on a 1920x1080 baseline. The scaling logic itself is shared, but you might need platform-specific tweaks for things like safe areas or overscan.
Production streaming apps tend to use OS-specific media players for optimal performance. You can either follow that path, using native implementations per OS, or use an abstraction to work across, like react-native-video (which now has Vega support). Unless you use these abstractions, your media implementations should live in your OS-specific packages.
Content Launcher, In-App Purchase, Amazon Device Messaging, and similar features currently need separate implementations for Vega and Fire OS because their underlying APIs are OS-specific. We're working to migrate these behind single RN libraries, but for now, structure these implementations so they're easy to consolidate later. Keep them in your platform packages with clean interfaces that shared code can call through.
Worth flagging early, simple VUIC components like Button and Text migrate easily to standard React Native equivalents. But Carousel and SeekBar need more work to replace. Identify these dependencies during your analysis phase so you're not surprised mid-migration.
Anything that touches native code directly (custom TurboModules, DRM implementations, hardware-specific features) stays platform-specific. No way around it.
The fastest way to see this in action is the Multi-TV Hello World repo. It's a hello-world project with a shared Header component that renders across Vega, Android TV, Apple TV, and Web from the same codebase.
For something that's closer to a production app, check out the React Native Multi-TV App Sample. This is a TV app template with:
Video playback via react-native-video
Spatial navigation with React TV Space Navigation
Drawer navigation, grid layouts, and a dynamic hero banner
Remote control support across all platforms
A shared UI library (@multi-tv/shared-ui) with platform-specific file resolution
It supports Android TV, Apple TV, Fire TV (Fire OS), Fire TV (Vega OS), and Web from a single monorepo. This is a good reference for how the shared workspace pattern holds up at scale.
We've also packaged our migration process into a three-phase agent skill that works with Kiro, Claude, or other AI coding assistants. It's available on GitHub: vega-multi-tv-migration.
To use it with Kiro, copy the vega-multi-tv-migration directory into ~/.kiro/skills/ and start a conversation about migrating your app. It activates automatically based on your conversation context.
The skill runs static code analysis and gives you an executive summary with estimated code reuse percentage, a dependency classification (what goes to shared, what stays OS-specific, what VMRP handles), and a screen-by-screen migration plan.
"Analyse my Vega app for multi-platform migration."
This creates the monorepo scaffold, moves code into shared and vega packages, configures Metro for monorepo resolution, and sets up VMRP. After this step, your Vega app should build and run exactly as before, but with shared code properly separated.
"Convert my Vega project to a yarn workspaces monorepo using the analysis from Phase 1."
This sets up the Expo TV package and implements replacements for Vega-specific dependencies:
@amazon-devices/kepler-player-client becomes react-native-video
@amazon-devices/kepler-ui-components becomes custom components or community libraries
@amazon-devices/kepler-file-system becomes expo-file-system
"Add Android TV and Apple TV support using Expo TV. Replace my Vega-specific dependencies with stock React Native equivalents."
Don't just take our word for it some of our partners are already building multi-platform TV apps with Vega and seeing real results. Check out how developers are reusing their React Native Vega code across TV operating systems in our developer community, or read about how Vega enabled Zattoo to streamline their TV app development across multiple platforms. These case studies show the practical benefits of the shared workspace approach in production environments.
A few things we've learned the hard way:
Clean up before migration: AI tools migrate code as is, including unused files and existing bugs - Do some optimization first.
Manage React Native version deltas: Platforms don't need identical RN versions but keep the delta to 4-6 versions max for third-party library compatibility.
Test on real devices: Emulators are great for development but validate on real hardware before shipping. TV apps behave differently on actual TVs - shocking, I know 😱.
Prebuild targets separately first: Get each target running independently before building together to save you some debugging headache.