React Native + Expo AI Rules

Rules for Expo-based React Native: file-based routing with expo-router, NativeWind for styling, EAS for builds, and platform-aware patterns that keep iOS and Android in sync.

TypeScriptReact Native#react-native#expo#expo-router#mobileLast updated 2026-05-05
tune

Want to customize this rules file? Open the generator with this stack pre-loaded.

Open in generatorarrow_forward

Save at .cursor/rules/main.mdc

React Native + Expo

Project context

This is a React Native app using Expo's managed workflow with file-based routing via expo-router. We target iOS and Android from a shared codebase. EAS handles builds and submissions; we don't manage native projects manually.

Stack

  • Expo SDK 51+ (managed workflow)
  • React Native 0.74+
  • TypeScript strict mode
  • expo-router v3+ for file-based routing
  • NativeWind v4 for Tailwind-style styling
  • expo-image for image rendering (not the bare RN <Image>)
  • react-native-reanimated for animations
  • React Query (TanStack) for server state
  • zustand for global UI state
  • expo-secure-store for tokens / sensitive data
  • pnpm or bun

Folder structure

app/
  _layout.tsx           — root layout (Stack / Tabs / Drawer)
  (tabs)/               — tab group
  (auth)/               — auth-only routes
  [id].tsx              — dynamic route
components/             — reusable components, organized by feature
hooks/
lib/                    — utilities, API client
constants/              — theme, sizes, etc.
assets/                 — images, fonts

Routing

  • File-based routing only — never react-navigation directly
  • Layout files (_layout.tsx) define stack/tabs/drawer for a segment
  • Use useLocalSearchParams() for dynamic params (typed)
  • Use <Link> for navigation; router.push() for programmatic
  • Use route groups (name)/ to share a layout without affecting URLs
// app/_layout.tsx
import { Stack } from 'expo-router'
export default function RootLayout() {
  return <Stack screenOptions={{ headerShown: false }} />
}

Components

  • Functional components, named exports only
  • Props typed inline; children: React.ReactNode
  • Use expo-image's <Image> over RN's built-in (better caching, perf)
  • Use expo-router's <Link> over Pressable-wrapped navigations

Styling with NativeWind

  • All styles via className (NativeWind compiles to RN styles)
  • Use semantic Tailwind classes (bg-background, text-on-surface) defined in tailwind.config.ts
  • For platform-specific styles: className="ios:pt-12 android:pt-8"
  • For dark mode: configure in _layout.tsx; use dark: variants

Platform differences

  • Use Platform.OS === 'ios' only when behavior must diverge
  • Prefer .ios.tsx / .android.tsx file extensions for substantially different implementations
  • Always test critical flows on both platforms before claiming done

Async storage

  • Tokens / sensitive data: expo-secure-store (encrypted)
  • Cache / non-sensitive data: @react-native-async-storage/async-storage
  • Form state, ephemeral UI: in-memory only

Networking

  • One API client at lib/api.ts, typed
  • Use TanStack Query for server state — handles caching, retries, focus refetch
  • Set sensible staleTime on every query — mobile is sensitive to network thrash
  • Handle offline explicitly: react-native-netinfo for network state, optimistic updates for mutations

Performance

  • Use expo-image for caching; specify contentFit and placeholder
  • Use FlatList (or FlashList) for any list over ~20 items
  • Set keyExtractor and getItemLayout when item heights are known
  • Avoid inline functions in renderItem — extract to a memoized component
  • Use useCallback and React.memo for list-row components specifically (this is one place memoization actually pays off)

EAS / builds

  • eas build --profile development for dev client builds
  • eas build --profile preview for internal testing
  • eas build --profile production for App Store / Play Store
  • eas submit for store uploads
  • Don't run npx react-native run-ios directly — that's bare workflow

Patterns to avoid

  • react-navigation direct usageexpo-router wraps it; use the router
  • Class components — hooks only
  • StyleSheet.create when NativeWind would do — keep all styles in className
  • Image from React Native — use expo-image
  • AsyncStorage for tokens — use expo-secure-store
  • Synchronous storage reads in render — always async, behind a state machine
  • Mixing useEffect with navigation — listen to router events instead

Testing

  • Unit tests with Jest + @testing-library/react-native
  • Detox or Maestro for end-to-end flows on a real device
  • Smoke-test on both iOS and Android before declaring done

Tooling

  • pnpm start or npx expo start — dev server
  • eas build — produce installable builds
  • eas update — over-the-air updates
  • pnpm lint — ESLint
  • pnpm typecheck — TypeScript

AI behavioral rules

  • Default to expo-router for navigation; never propose react-navigation directly
  • Use NativeWind classes; don't reach for StyleSheet.create unless dynamic
  • Use expo-image, not RN's Image
  • Store tokens in expo-secure-store, never AsyncStorage
  • Test changes on both iOS and Android before claiming done
  • Don't add native modules without surfacing the eject implications
  • Run lint, typecheck, and tests before declaring a task complete

Frequently asked

How do I use this React Native rules file with Cursor?

Pick "Cursor (.cursor/rules/*.mdc)" from the format dropdown above and click Copy. Save it at .cursor/rules/main.mdc in your project root and restart Cursor. The legacy .cursorrules format still works if you're on an older Cursor version — pick that option instead.

Can I use this with Claude Code (CLAUDE.md)?

Yes — pick "Claude Code (CLAUDE.md)" from the format dropdown above and copy. Save the file as CLAUDE.md at your repo root. Claude Code reads it automatically on every session. For monorepos, you can also drop nested CLAUDE.md files in subdirectories — Claude merges them when working in those paths.

Where exactly do I put this file?

It depends on the AI tool. Cursor reads .cursorrules or .cursor/rules/*.mdc at the project root. Claude reads CLAUDE.md at the project root. Copilot reads .github/copilot-instructions.md. The "Save at" path under each format in the dropdown shows the exact location for the format you picked.

Can I customize these React Native rules for my project?

Yes — that's what the generator is for. Click "Open in generator" above and the wizard loads with this stack's defaults pre-selected. Toggle on or off the conventions you want, then re-export in your AI tool's format.

Will using this rules file slow down my AI tool?

No. Rules files count toward the model's context window but not toward latency in any noticeable way. The file is loaded once per session, not per token. The library files target 250–400 lines, well within every tool's recommended budget.

Should I commit this file to git?

Yes. The rules file is project documentation that benefits every developer using the AI tool. Commit it. The exception is personal-global settings (e.g. ~/.claude/CLAUDE.md) which are user-scoped and stay out of the repo.

Related stacks