Guide · for the owner of a React or Next.js codebase who wants it on phones

    Convert a React app to a native mobile app: what maps from your codebase, what doesn’t, and the three ways to do it

    The most common assumption we hear from people with a React web app is that React Native is a port target: same language, same components, swap the build. It isn’t. React Native renders native components from JavaScript and shares React’s programming model, not React’s UI — your components, CSS and browser code don’t run there. This page goes through a React or Next.js codebase file by file: what carries over unchanged, what carries over as a shape, what is rebuilt, and the three ways to get to a native app on both stores.

    Verified

    What “React to mobile” actually means. A React web app has four layers: the UI (components, JSX, CSS or Tailwind, the DOM and browser APIs), the app logic (state shape, reducers or hooks, validation, the rules of the product), the data layer (API calls, the auth provider, the database behind them), and, in Next.js, a server side (route handlers, SSR, middleware). A phone app keeps the bottom layers and rebuilds the top one. That is true whether the phone app is React Native — in Rork’s documentation’s words, “one JavaScript codebase that renders native UI on both iOS and Android”, which means new components, not your web ones — or native Swift and Kotlin. The decision is not “port or rebuild”; the screens are rebuilt either way. The decision is what they are rebuilt in and who does it.

    What maps, file by file

    Routes → screens. Every route in your app (/dashboard, /items/[id], /settings) is a screen in the phone app, and your route tree is the navigation map. This is the most valuable thing in the repo for whoever does the rebuild: it is the screen list.

    API calls → the same API. Every fetch, every client call to your backend, carries over as a contract: same endpoints, same payloads, same auth header. The phone app calls what the web app calls.

    Auth → the same provider, native SDK. If the web app signs in with Supabase, Firebase, Clerk or Auth0, the phone app uses that provider’s native SDK against the same user table. Users don’t re-register. With Supabase, the iPhone app uses Supabase’s own Swift client and the Android app the community-maintained Kotlin client.

    State shape → the same state shape. What each screen needs to know (the list, the selected item, loading, error) is the same on the phone; the reducer or hook that produces it is a spec for the native version, even when the code is rewritten.

    Validation and business rules → re-implemented, unchanged in meaning. The rules that live in the client (form validation, what a user may do) are rewritten in the new language from the existing code; rules that live on the server stay there.

    Next.js server side → stays on the server. Route handlers, middleware and anything SSR does are server code; the phone app calls them over HTTP like any other client. Nothing server-side moves into the app.

    What doesn’t map

    Components and JSX. A <div> with a className is a DOM instruction. React Native has no DOM; native has no React. The screen is rebuilt with the platform’s parts — SwiftUI and Jetpack Compose, or React Native’s own components.

    CSS, Tailwind, styled-components. No equivalent on a phone; layout is redone in the platform’s layout system. Design tokens (colors, spacing, type scale) carry over as values, not as stylesheets.

    Browser APIs. window, document, localStorage, the History API, service workers, anything DOM-shaped — replaced by platform equivalents (Keychain and app storage, native navigation, background tasks).

    Web-only libraries. Charting, rich text, maps, date pickers built for the DOM are replaced by native or React Native equivalents; the data they render carries over.

    Responsive layout. A phone app is one layout per platform, not a breakpoint; the iPhone Duo’s split layout, for example, comes from Apple’s own containers, not from a media query.

    The three ways to get the native app

    1. React Native, by hand. A developer rebuilds the screens in React Native components, keeps your API and auth, and ships one JavaScript codebase for both stores. Closest language to what you have; still a rebuild of every screen; the result is a cross-platform framework app, which React Native vs native compares honestly.

    2. Native Swift and Kotlin, by hand. A developer reads the same repo — routes, API, auth, state — and rebuilds the screens in SwiftUI and Jetpack Compose. The phone app then uses the platform’s own parts and follows platform updates first. Two codebases; the brief is the one-page PRD with your route tree as the screen list.

    3. Native from the repo, with Modaal. Connect the GitHub repository; Modaal reads it the way the developer in route 2 would — routes, data model, API calls, auth — and writes a plan: the screen list, the features, what maps to what. You approve it before code. Then the agents rebuild feature by feature, the logic once, the SwiftUI screens for iPhone and the Jetpack Compose screens for Android, from one project, against the backend the web app already uses. From Modaal’s documentation: “Each feature’s logic — its state, the actions that change it, the effects it requests — is written once,” and “The iPhone app renders that state in SwiftUI; the Android app renders it in Jetpack Compose.” The Xcode and Android Studio projects are on your disk on every plan. Free for one project; Pro is €9 per user per month billed annually, €15 monthly, for both platforms, TestFlight and Git — /pricing. The product page is /web-to-native; the import is rolling out to early-access users in October 2026, and the list is on that page.

    How to prepare the repo, whichever route

    Three things make the rebuild — by a developer or by agents — go right. Write down the screen list from your route tree, one line per screen with what it must show and do; that is most of the PRD. Make sure the API is callable from outside the web app — the phone app is a separate client, so endpoints that assumed a same-origin cookie need a token. And open your own Apple Developer Program membership ($99 a year) and Google Play Console ($25 once) before the first build, so the app is published under your account, not a contractor’s.

    A React / Next.js codebase, layer by layer

    LayerExamplesCarries over?How
    Routesapp/ or pages/ tree, dynamic routesYes, as the screen listEach route becomes a screen; the tree is the navigation
    API callsfetch to your backend, tRPC/REST clientsYes, as a contractSame endpoints and payloads from the phone
    AuthSupabase, Firebase, Clerk, Auth0YesSame provider, native SDK, same users
    State shapereducers, hooks, storesYes, as a specSame state per screen; code rewritten in the new language
    Business rulesvalidation, permissions in the clientYes, in meaningRe-implemented from the existing code
    Server side (Next.js)route handlers, middleware, SSRStays on the serverCalled over HTTP like any client
    Components / JSXdiv, forms, listsNoRebuilt with platform parts (SwiftUI, Compose) or RN components
    CSS / Tailwindstylesheets, utility classesNoLayout redone natively; tokens carry over as values
    Browser APIswindow, localStorage, service workersNoPlatform equivalents
    Web librariesDOM charts, editors, mapsNoNative or RN equivalents; data carries over

    Structural; applies to React Native and native targets alike. What differs between the two targets is the language the top layer is rebuilt in.

    Frequently asked questions

    Not as a port. React Native shares React’s programming model but renders native components, so your web components, CSS and browser code don’t run there; the screens are rebuilt. What carries over is the route tree as the screen list, the API calls, the auth provider, the state shape and the business rules. The same is true for a native Swift and Kotlin rebuild — the difference is the language the screens are rebuilt in.

    Yes, with the server side staying where it is. Route handlers, middleware and SSR are server code and are called from the phone over HTTP like any other client; the pages become screens, rebuilt natively or in React Native, against the same API and auth.

    The parts that aren’t UI: the API contract, the auth setup, the state shape, the validation and rules, and the route tree as a map. The UI layer — components, JSX, CSS, browser APIs, web-only libraries — is rebuilt. This page doesn’t give a percentage because it depends on how much of your app is UI.

    React Native keeps you in JavaScript and gives one codebase for both stores; native gives the platform’s own parts and follows platform updates first, at the cost of two codebases unless the tool writes the logic once for both. Either way the screens are rebuilt. React Native vs native has the full comparison; the decision is about the product, not about how much React you already have.

    It can do the rebuild, not a translation: read the repository’s routes, data model, API and auth, propose the screen list and features as a plan, and write the native screens from it against your existing backend. Modaal’s import does this from a GitHub repository, with the plan approved before code and the Xcode and Android Studio projects on your disk.

    No, if the phone app uses the same auth provider through its native SDK — Supabase, Firebase, Clerk, Auth0 — against the same user table. The one thing to check is that your API accepts a token from a non-browser client rather than relying on a same-origin cookie.

    A one-line-per-screen list from your route tree (what each screen shows and does), an API that accepts a token from a separate client, backend credentials, and your own Apple and Google developer accounts so the app is published under your name. That set is the input for a developer and for the import alike.

    Your routes are the screen list. Connect the repo.

    Modaal reads a React or Next.js repository, writes a plan you approve, and rebuilds the screens as native iOS and Android apps from one project — same API, same auth, your own AI agent. Free for one project.

    Keep reading