Skip to content

Repository files navigation

React Native Template

Modern Expo + React Navigation template with a small, production-oriented baseline: typed navigation, a theme system, i18n, and a lightweight state setup.

Features

Core

  • React Native: 0.88.0-rc.3 + React 19.3.0 (New Architecture)
  • Expo: SDK 58 (preview / expo@next)
  • Navigation: React Navigation 7 (tabs, stacks, modals)
  • TypeScript: strict type checking
  • Package manager: bun (bun install, bun.lock)

Styling & Theme

  • Styling: react-native-unistyles for RN views + @expo/ui style/textStyle on native trees
  • Theming: light/dark mode + system theme sync (Legend State store bridged to UnistylesRuntime)
  • Design tokens: colors, spacing, typography, radii, shadows

UI

  • UI: @expo/ui universal components (Host, Button, Text, Column, Row, etc.)
  • Pressable: local gesture-handler pressable kept for custom hit targets
  • Layouts: Base/Bare/Modal layouts for screens

State / Storage / Tooling

  • State: Legend State with MMKV persistence
  • Forms: React Hook Form
  • List rendering: LegendList v3 utility wrapper
  • Monetization: RevenueCat utility
  • Quality: Oxlint + Oxfmt + Lefthook

Project Structure

src/
├── components/         # Common, layouts
├── hooks/              # App-level hooks (debounce/throttle/etc.)
├── i18n/               # i18next setup + locales (en)
├── navigation/         # Navigators, linking, param lists
├── providers/          # Top-level providers (ErrorBoundary, etc.)
├── screens/            # Screen UI rendered by navigators
├── stores/             # App stores (settings, etc.)
├── theme/              # Theme system (tokens, hooks, store, unistyles registry)
├── types/              # Shared TS types
└── utils/              # Utilities (storage, logger, date, etc.)

Getting Started

brew install oven-sh/bun/bun   # or: curl -fsSL https://bun.sh/install | bash
bun install
bun run start

Run native:

bun run ios
bun run android

Add or remove dependencies with bun add / bun remove; bun owns the lockfile (bun.lock), so npm install, pnpm install, and expo install must not be used to change the tree.

App variants

Development and production installs can sit side by side. app.json holds the production identity; app.config.ts suffixes it when APP_VARIANT is not production.

Variant APP_VARIANT Name Bundle ID / package
Dev (default) development or dev my-template-app (Dev) com.mytemplateproject.dev
Preview preview my-template-app (Preview) com.mytemplateproject.preview
Production production my-template-app com.mytemplateproject

Local scripts (start, ios, android, prebuild) set APP_VARIANT=development. EAS profiles in eas.json set the same variable per build. Only the development build registers the generated exp+<slug> scheme so the Metro QR code opens the Dev app.

Read the resolved variant at runtime with Constants.expoConfig?.extra?.variant. Register each identifier separately with Sentry, and any other service keyed to bundle ID.

Switching a local native project to another variant:

APP_VARIANT=production bunx expo prebuild --clean

Use APP_VARIANT=development bunx expo prebuild --clean before the next dev session so CLI schemes point at the Dev app again.

Usage

UI Components

Use @expo/ui universal components wrapped in Host.

import { Button, Host, Text } from "@expo/ui";

export function Example() {
  return (
    <Host matchContents>
      <Text textStyle={{ fontSize: 24, fontWeight: "600" }}>Welcome</Text>
      <Button label="Continue" onPress={() => {}} />
    </Host>
  );
}

Styling

RN views are styled with react-native-unistyles. Import StyleSheet from react-native-unistyles (never react-native), define styles at module level, and reach theme tokens through the theme callback argument. Styles update automatically on light/dark change — no hook needed.

import { View } from "react-native";
import { StyleSheet } from "react-native-unistyles";

const styles = StyleSheet.create((theme) => ({
  card: {
    padding: theme.spacing[4],
    borderRadius: theme.borderRadius.lg,
    backgroundColor: theme.colors.surface.elevated,
  },
}));

export function Card() {
  return <View style={styles.card}>{/* ... */}</View>;
}

Avoid inline style={{...}} on RN views and theme reads in JSX. @expo/ui props (style, textStyle on Host/Column/Text, …) are @expo/ui's own API and stay inline.

The unistyles themes are registered in src/theme/unistyles.ts; the light/dark decision itself lives in the Legend State theme store (themePrefs$) and is bridged to UnistylesRuntime.setTheme on every mode change.

Theming

import { Button, Host, Text } from "@expo/ui";
import { useTheme } from "@/theme";

export function ThemeExample() {
  const { mode, isDark, toggleMode } = useTheme();

  return (
    <Host colorScheme={isDark ? "dark" : "light"} matchContents>
      <Text>
        Mode: {mode} ({isDark ? "dark" : "light"})
      </Text>
      <Button label="Toggle theme" onPress={toggleMode} variant="outlined" />
    </Host>
  );
}

Internationalization

This template ships with English resources by default. Add more languages by extending src/i18n/locales/* and resources in src/i18n/index.ts.

Subscriptions

Subscriptions use RevenueCat (react-native-purchases + react-native-purchases-ui). Set the public SDK keys in .env:

  • EXPO_PUBLIC_REVENUECAT_IOS_API_KEY
  • EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY

The wrapper expects a premium entitlement and paywall placements settings and onboarding_v1 in the RevenueCat dashboard. Initialization is skipped when the current platform key is missing.

Expo Go can load the SDK in Preview API Mode, but real purchases require a development build. After adding or changing these native packages, remake the native client (bun run prebuild or an EAS development build).

Scripts

  • bun run start - start Expo dev server
  • bun run ios - run iOS build
  • bun run android - run Android build
  • bun run lint - run Oxlint with auto-fix
  • bun run format - check formatting with Oxfmt
  • bun run format:write - format with Oxfmt
  • bun run typecheck - TypeScript typecheck
  • bun run prebuild - regenerate native projects (APP_VARIANT=development with prebuild:dev)

About

Modern React Native & Expo SDK 58 template with React Navigation 7, Unistyles, Legend State, MMKV, Sentry, RevenueCat, i18next, and TypeScript.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages