Skip to content

React Native + Expo Rules

Cursor.cursorrulesCoding

Expo project rules covering typed expo-router navigation, platform-split files, asset and font handling, and list performance.

Use when: Use in Expo SDK 50+ apps with expo-router and TypeScript to keep navigation type-safe and platform-specific code contained.

@library0 upvotes0 remixes0 comments

Get this skill

Add the skill file with the CLI, by hand, or over MCP.

Save this to your project or home directory so Cursor can load it.

npx goodprompts add react-native-expo-cursorrules
Saves to./.cursorrules
npx goodprompts add react-native-expo-cursorrules
Saves to ./.cursorrules

Skill file

.cursorrules3,493 characters
You are working in an Expo (managed workflow) app with expo-router and strict TypeScript.
## Navigation
- expo-router file-based routes only — never install or generate raw `@react-navigation` stack/tab setup by hand; expo-router wraps it.
- Typed routes are on (`experiments.typedRoutes: true` in app.json). Navigate with `<Link href="/profile/[id]" />` or `router.push({ pathname: "/profile/[id]", params: { id } })` — never a template-string path, which bypasses route typing.
- Read params with `useLocalSearchParams<{ id: string }>()` and validate/coerce immediately; params are always strings.
- Route groups organize layout, not URLs: auth screens under `app/(auth)/`, tabs under `app/(tabs)/`. Screens private to a route live in a co-located `components/` folder outside `app/` (only routes live in `app/`).
- Auth gating happens in a layout via `<Redirect href="/sign-in" />` after the session loads — never `router.replace` inside a screen's `useEffect`.
## Platform splits
- One `Platform.OS` ternary in a file is fine. Two or more, or any platform-specific JSX block, means split the file: `haptics.ios.ts` / `haptics.android.ts` with a shared `haptics.d.ts` (or a common `.ts` fallback) so imports stay `./haptics`.
- Platform-specific styling constants (shadows vs elevation, status-bar padding) live in one `theme/platform.ts`, computed once with `Platform.select` — not inline `Platform.select` scattered through StyleSheets.
- Never assume safe-area insets: wrap screens in `SafeAreaView` from `react-native-safe-area-context` (not the core one) or use `useSafeAreaInsets()` for fine control.
- Web is a target too: no direct `window`/`document` access outside `.web.ts` files; check `Platform.OS === "web"` before native-only modules.
## Assets, fonts, images
- Static assets are imported (`require("@/assets/images/logo.png")`) so Metro bundles and hashes them — never hardcoded file paths or remote URLs for things that ship with the app.
- Use `expo-image` (`<Image>` with `contentFit`, `transition`, `cachePolicy`) instead of core `Image` everywhere. Give every remote image an explicit size or flex constraint; an unsized image is a layout bug.
- Fonts load via `expo-font` config plugin in app.json (embedded at build time), not runtime `useFonts`, unless the font is genuinely dynamic.
- Icons come from `@expo/vector-icons` only; no ad-hoc icon PNGs.
## Components and style
- `StyleSheet.create` at file bottom, or NativeWind classes if the project has it — never inline style objects in JSX (they re-allocate every render), except a single dynamic value merged as `[styles.box, { height }]`.
- Long lists: `FlashList` (or `FlatList` with `keyExtractor` returning a stable id). Never render a list by `.map` inside a `ScrollView` past ~10 items.
- Touchables: `Pressable` with `hitSlop` of at least 8 on small targets; no deprecated `TouchableOpacity` in new code.
- Keyboard handling on every form screen: `KeyboardAvoidingView` with `behavior={Platform.OS === "ios" ? "padding" : "height"}`, plus `keyboardShouldPersistTaps="handled"` on the enclosing scroll view.
## Config and native modules
- Secrets and environment switches go through `app.config.ts` `extra` + `expo-constants` (or `EXPO_PUBLIC_*` vars for client-safe values) — never a committed `.env` read at runtime.
- Any library with native code must be Expo-compatible (config plugin or included in the Expo SDK). Adding one means a new dev client build — call that out in the PR description.
Comments

Comments

Sign in to commentSign in

Remixes

Loading remixes…