How I architected an OTT streaming platform that ships to web, mobile, TV, and desktop from one Nx monorepo.
Prachyam Studios needed a streaming platform. Not just a web app — they needed apps for Android, iOS, Android TV, Apple TV, Roku, Fire TV, LG webOS, Samsung Tizen, and desktop. Oh, and a web app too. And an admin panel. And a content management system.
Building separate codebases for each platform? That's 12+ repos with duplicated business logic, diverging APIs, and a maintenance nightmare.
Nx gives you a monorepo with intelligent build caching, dependency graph awareness, and the ability to share code across projects. Combined with React Native (for mobile/TV) and React (for web), it was the right tool.
Karanveer Singh Shaktawat
Full Stack Engineer & Infrastructure Architect
Building portfolio, contributing to open source, and seeking remote full-time roles with significant technical ownership.
Pick what you want to hear about — I'll only email when it's worth it.
Did this resonate?
How I architected a full-stack OTT streaming platform for web, mobile, four TV OSes, and a desktop admin panel — solo, in one Nx TypeScript monorepo — and what I'd do differently.
apps/
mobile/ # React Native (Android + iOS)
tv-android/ # React Native for Android TV
tv-apple/ # React Native for tvOS
tv-roku/ # Roku (BrightScript, separate build)
tv-fire/ # Fire TV (React Native fork)
tv-lg/ # LG webOS (React-based)
tv-samsung/ # Samsung Tizen (React-based)
web/ # Next.js web app
admin/ # Next.js admin panel
desktop/ # Electron wrapper
libs/
shared/
api/ # API client, auth, types
ui/ # Shared UI components
hooks/ # Custom hooks (usePlayer, useAuth, etc.)
utils/ # Helpers, formatters, validators
constants/ # Config, feature flags
platform/
tv-navigation/ # TV-specific D-pad navigation
mobile-gestures/ # Touch gesture handlersThe key insight: 80% of the code is platform-agnostic. Authentication, API calls, state management, business logic, types — all shared. Only the rendering layer and platform-specific features differ.
// libs/shared/hooks/usePlayer.ts
export function usePlayer(contentId: string) {
const [state, dispatch] = useReducer(playerReducer, initialState);
const api = useApiClient();
const play = useCallback(async () => {
const stream = await api.getStream(contentId);
dispatch({ type: 'PLAY', payload: stream });
}, [contentId, api]);
const pause = useCallback(() => {
dispatch({ type: 'PAUSE' });
}, []);
return { ...state, play, pause };
}This hook works everywhere — the platform-specific player component just wraps the native video implementation (ExoPlayer on Android, AVPlayer on iOS, etc.).
TV apps don't have touch or mouse — they have a D-pad (up, down, left, right, select). I built a shared navigation system:
// libs/platform/tv-navigation/useFocusGrid.ts
export function useFocusGrid(rows: number, cols: number) {
const [focused, setFocused] = useState({ row: 0, col: 0 });
const handleKey = useCallback((direction: Direction) => {
setFocused(prev => {
switch (direction) {
case 'up': return { ...prev, row: Math.max(0, prev.row - 1) };
case 'down': return { ...prev, row: Math.min(rows - 1, prev.row + 1) };
case 'left': return { ...prev, col: Math.max(0, prev.col - 1) };
case 'right': return { ...prev, col: Math.min(cols - 1, prev.col + 1) };
}
});
}, [rows, cols]);
return { focused, handleKey };
}Nx's computation cache was a game-changer. A full build of all 12 apps from scratch takes ~15 minutes. But with cache hits, pushing a change to the shared API layer and rebuilding all affected apps takes under 2 minutes.
# Only rebuilds what changed
npx nx affected --target=build
# Remote cache for CI (with Nx Cloud)
npx nx run-many --target=build --all --parallel=4usePlayer breaks, it breaks everywhere.The monorepo approach isn't free, but for multi-platform products, the alternative is far more expensive.
How I designed the code structure for a streaming platform targeting Next.js web, React Native iOS/Android, tvOS, Android TV, and Tauri desktop — shared business logic, platform-specific UI, one repo.