MENU
React Native
React Native lets you build a genuinely separate native app -- one that compiles down to real iOS and Android views, not a browser rendering HTML -- while reusing the React mental model you already use in Next.js: components, props, state, hooks, and a declarative render function. It is the option on the "going mobile" spectrum that involves the most new code, but it's also the only one that gives you a fully native look, feel, and performance profile.
Same mental model, different rendering target
This is the single most important thing to understand about React Native: it is React, but it is not the DOM. A Next.js component renders to HTML elements like <div> and <p>, which the browser paints. A React Native component renders to native platform views -- <View> and <Text> instead of <div> and <p> -- which iOS and Android render using their own native UI toolkits. There is no HTML, no CSS in the browser sense (styling uses a JavaScript object syntax modeled on CSS, applied via StyleSheet), and no DOM APIs like document or window.
app,(tabs),index.tsx (Next.js Client Component):
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div style={{ padding: 16 }}>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}screens,Counter.tsx (React Native):
import { useState } from 'react'
import { View, Text, Pressable, StyleSheet } from 'react-native'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<View style={styles.container}>
<Text>Count: {count}</Text>
<Pressable onPress={() => setCount(count + 1)}>
<Text>Increment</Text>
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
container: { padding: 16 },
})Expo: the common way to start today
Expo is a toolchain and set of managed services built on top of React Native that handles the native build process, over-the-air updates, and a large library of pre-built native modules (camera, location, notifications, and more) without requiring you to touch Xcode or Android Studio for most day-to-day work. Starting a new React Native project today almost always means running Expo's CLI rather than configuring the bare React Native toolchain by hand -- it's the closest equivalent to how create-next-app gets you started on the web side.
Expo Router, in particular, is worth calling out because it deliberately mirrors Next.js's file-system based App Router: routes are files under an app/ folder, nested folders create nested routes, and files named [param].tsx create dynamic segments. The routing concepts transfer almost directly; the actual screen components underneath still render React Native primitives, not HTML.
terminal:
npx create-expo-app@latest my-app --template tabs
cd my-app
npx expo startWhat can realistically be shared with your Next.js app
"Learn once, write anywhere" was React Native's original tagline, and it's more accurate than "write once, run anywhere" -- expect to share knowledge and some logic, not entire screens. In practice:
| Can typically be shared | Business logic, validation functions, date/formatting utilities, TypeScript types, an API client built on fetch, state management stores (Zustand, Redux), and any hook that doesn't touch the DOM or browser-only globals. |
| Cannot be shared | Anything rendering JSX for the DOM (your Next.js pages, layouts, and components), Server Components, Server Actions, Route Handlers, and any Next.js routing/config file -- these have no equivalent runtime in React Native, which has no server and no HTML. |
| Shareable with adaptation | Hooks that call browser APIs (localStorage, window) need a React Native equivalent (AsyncStorage, Dimensions) behind the same interface; styling has to be reimplemented per platform since there is no CSS. |
The most effective way to maximize sharing is to keep an isolated, framework-agnostic package (in a monorepo, for example) for your business logic and API layer, and treat both the Next.js app and the React Native app as thin UI shells that import from it -- rather than trying to share components directly, which rarely works cleanly given how different the two render targets are.
When to reach for this instead of a WebView or Capacitor
Building a real React Native app is the right call when you need native navigation gestures and animations, tight integration with native APIs (camera, Bluetooth, background tasks, push notifications) beyond what a plugin bridge exposes, or the best possible runtime performance for complex UI. If you mainly want an app-store presence for content you've already built as a Next.js site, the lighter-weight React Native WebView or Capacitor approaches get you there with far less new code.