NNextron Docs

React Native (Expo)

The Expo stack — a React Native app on Expo SDK 56 with Expo Router and NativeWind, standalone or in a monorepo with the same modular Express backend, plus mobile screens for auth, payments, AI, and tRPC.

The React Native (Expo) stack generates a mobile app on Expo SDK 56 using Expo Router (file-based routing) and NativeWind (Tailwind CSS for React Native). Because a mobile app is a client — it can't host a database, ORM, or webhooks — the stack pairs it with the same Express backend as the Vite + Node stack, and reuses every express-* module. Choose it at the first nextron create prompt.

Layouts

  • App only — a standalone Expo app at the project root that talks to an external backend via EXPO_PUBLIC_API_URL. Backend files are never generated; only the client screens and services are.
  • Monorepo — a pnpm workspace with apps/mobile (the Expo app) and apps/api (the same modular Express backend). The mobile app defaults to EXPO_PUBLIC_API_URL=http://localhost:4000, matching the API's default port.

Mobile app architecture

The Expo app follows the same separation of concerns as the web app in the Vite + Node stack, so screens stay thin and API access stays in one place:

app/                       # Expo Router screens (file-based routing)
  _layout.tsx              # root layout — renders <Providers><Stack/></Providers>
  index.tsx                # home screen (modules inject nav links)
  (auth)/                  # route groups added by modules (e.g. sign-in/up)
src/
  shared/
    env.ts                 # zod-validated EXPO_PUBLIC_* env
    lib/api.ts             # the HTTP transport — ONLY services import this
    providers.tsx          # composes context providers (modules inject here)
    components/NavLink.tsx  # home-screen link card
  modules/
    <feature>/
      services/            # all API calls for the feature live here
      components/          # feature UI
      hooks/               # feature hooks
  • Never call api() from a screen. Screens call a service (modules/<feature>/*.service.ts); only services import the api transport. This keeps request/response shapes, endpoints, and error handling in one testable layer.
  • Routing is file-based: a module drops a screen file under app/ and it is routed automatically — no route registry to edit. Modules add home-screen links at the nextron:mobile-nav marker in app/index.tsx.
  • Providers are composed in src/shared/providers.tsx. Modules wrap their provider (session, tRPC, Stripe) at the nextron:mobile-providers-open / nextron:mobile-providers-close markers — the same marker mechanism the backend uses for routes.
  • The @/ alias maps to src (configured in tsconfig.json).
  • Auth wires a token provider into the transport, so every request automatically carries Authorization: Bearer <token> once signed in — services never set it by hand. The token is persisted in the device keychain via expo-secure-store.

Environment

Only variables prefixed EXPO_PUBLIC_ are inlined into the app bundle — never put secrets in the client. The generated src/shared/env.ts validates them with zod at startup.

VariablePurpose
EXPO_PUBLIC_API_URLBase URL of the backend the app talks to
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEYStripe publishable key (added with the Stripe module)

Modules

Every module's backend files target apps/api, exactly as in the Vite + Node stack; its mobile screens and services target apps/mobile (or the project root for app-only projects).

ModuleMobile surface
express-authSign-in / sign-up screens, a useSession() hook, and secure-store token storage. Requires a database module for the backend user store.
stripe-expressA native PaymentSheet checkout screen (@stripe/stripe-react-native) and a StripeProvider.
polar-expressA checkout screen that opens Polar's hosted checkout in the browser (expo-web-browser).
express-aiA chat screen that streams from the backend POST /api/ai/chat.
express-trpcA typed tRPC client + React Query provider. Import AppRouter from the backend for end-to-end type-safety.
express-database, express-inngestBackend only — no mobile surface.

For the backend behavior of these modules (endpoints, webhooks, databases, JWT auth), see the Express backend guide.

Commands

# Monorepo (from the workspace root)
pnpm dev          # runs the API and the Expo dev server in parallel
pnpm dev:api      # API only
pnpm dev:mobile   # Expo dev server only

# Inside the app (app-only, or apps/mobile)
npx expo start    # start Metro
npm run ios       # / android / web
pnpm typecheck

Dependency versions

The generated package.json pins a coherent Expo SDK 56 set, but transitive native versions move fast. If install or the dev build complains about a version, run npx expo install --check (or npx expo install <package>) inside the app to reconcile every dependency with your installed SDK — Expo's resolver is the source of truth.

Adding modules

Modules are stack-aware. The express-* modules apply to both the Vite + Node and Expo stacks; Next.js modules (auth, trpc, dashboard, …) cannot be added to an Expo project. In a monorepo, run nextron add from apps/api, where nextron.config.ts lives — the backend side is wired automatically; add the matching mobile screens under apps/mobile as needed.

On this page