This document outlines the standardized rules and guidelines for developing mobile applications using Expo and React Native. These rules are designed to ensure consistency, maintainability, performance, accessibility, and error-free development across all projects. They apply to all Expo-based React Native apps and are crafted to minimize troubleshooting efforts and enforce best practices.
- Mandatory Compliance: Cursor must read and strictly follow all rules in this document for every Expo and React Native project.
- Self-Check: Before generating code or modifying a project, Cursor must verify that its actions align with these guidelines.
- Error Prevention: If Cursor detects a potential violation of these rules (e.g., creating a new project inside an existing one), it must halt and prompt the user for clarification instead of proceeding.
- Documentation Reference: Cursor must reference this document (
cursor-rules.md) when suggesting project changes or scaffolding to ensure compliance.
- Write concise, technical TypeScript code with clear, accurate examples.
- Use functional and declarative programming patterns; avoid class-based components.
- Prioritize modularization and iteration to prevent code duplication.
- Use descriptive variable names with auxiliary verbs (e.g.,
isLoading,hasError,shouldRender). - Organize files in a consistent structure:
- Exported main component
- Subcomponents
- Helper functions
- Static content (e.g., constants, mock data)
- TypeScript types/interfaces
- Follow Expo's official documentation for project setup and configuration: https://docs.expo.dev/
- Keep components small and focused, with a single responsibility per component.
- Use barrel files (
index.ts) for exporting multiple modules from a directory. - Prevent Nested Projects: Cursor must never create a new Expo or React Native project inside an existing project. Before scaffolding, check for the presence of
app.json,package.json, ornode_modules. If detected, modify the existing project instead of initializing a new one. If unsure, prompt the user to confirm the project root.
- Use lowercase with dashes for directories (e.g.,
components/auth-flow,utils/api). - Use PascalCase for component names (e.g.,
AuthButton,ProfileCard). - Use camelCase for variables, functions, and hooks (e.g.,
fetchUserData,useAuthState). - Favor named exports for components and utilities (e.g.,
export function MyComponent). - Prefix custom hooks with
use(e.g.,useDeviceOrientation). - Use clear, intention-revealing names for files (e.g.,
AuthContext.ts,UserProfileScreen.tsx).
- Use TypeScript for all code; prefer interfaces over type aliases for object shapes.
- Avoid enums; use constant maps or union types instead.
- Enable strict mode in
tsconfig.jsonfor enhanced type safety. - Define interfaces for component props and state (e.g.,
interface MyComponentProps). - Use explicit return types for functions and avoid
anyunless absolutely necessary. - Leverage utility types (e.g.,
Partial,Pick,Omit) to reduce boilerplate. - Ensure all props and state are typed, including optional properties with
?.
- Use the
functionkeyword for pure functions to distinguish them from components. - Avoid unnecessary curly braces in conditionals; prefer concise syntax for simple statements (e.g.,
if (condition) return null). - Write declarative JSX with minimal logic; extract complex logic to hooks or helpers.
- Use Prettier for consistent code formatting with default settings:
- Single quotes
- Trailing commas
- 2-space indentation
- Enforce ESLint with React Native and TypeScript-specific rules for code quality.
- Avoid inline styles; use a styling solution (see UI and Styling).
- Use Expo's built-in components (e.g.,
View,Text,Image) for standard UI patterns. - Implement responsive design using Flexbox and Expo's
useWindowDimensionsfor dynamic layouts. - Choose a consistent styling approach:
- Option 1: Styled-components for component-scoped styles.
- Option 2: Tailwind CSS (via
nativewind) for utility-first styling. - Option 3:
StyleSheet.createfor vanilla React Native styles.
- Support dark mode using Expo's
useColorSchemehook. - Ensure high accessibility (a11y) standards:
- Use ARIA roles and native accessibility props (e.g.,
accessibilityLabel,accessibilityRole). - Test with screen readers (e.g., VoiceOver on iOS, TalkBack on Android).
- Ensure sufficient color contrast and touch target sizes (minimum 44x44 pixels).
- Use ARIA roles and native accessibility props (e.g.,
- Use consistent theming with a design system (e.g., define colors, typography, and spacing in a
theme.tsfile).
- Handle notches, status bars, and other screen insets dynamically.
- Use
SafeAreaViewfrom Expo or React Native to wrap top-level components. - For scrollable content, use a custom
SafeAreaScrollViewcomponent to respect safe area boundaries. - Avoid hardcoding padding or margins for safe areas; rely on safe area utilities or context.
- Minimize
useStateanduseEffect; prefer context or reducers for complex state management. - Optimize app startup with Expo's
SplashScreenfor a smooth loading experience. - Optimize images:
- Use WebP format where supported.
- Include size data (width/height) to prevent layout shifts.
- Implement lazy loading for images below the fold.
- Use code splitting and lazy loading for non-critical components with
React.lazyandSuspense. - Profile performance using React Native's built-in tools (e.g.,
PerformanceMonitor) and Expo's debugging features. - Prevent unnecessary re-renders:
- Memoize components with
React.memo. - Use
useMemoanduseCallbackfor expensive computations and callbacks.
- Memoize components with
- Limit re-renders in lists by using
keyprops and optimizingFlatList/SectionListcomponents.
- Implement navigation using a library or custom solution suitable for the project.
- Support deep linking for seamless navigation from external sources (e.g., push notifications, URLs).
- Ensure navigation state is preserved across app restarts using Expo's tools.
- Use type-safe navigation with TypeScript to prevent runtime errors.
- Use React Context with
useReducerfor global state management. - For data fetching, prefer a lightweight solution (e.g., custom hooks with
fetchoraxios). - For complex state, consider libraries like Zustand or Redux Toolkit.
- Avoid over-fetching; cache API responses where appropriate.
- Handle URL parameters and query strings using Expo's linking utilities.
- Implement robust error handling:
- Handle errors at the start of functions with early returns.
- Avoid nested
ifstatements; use theif-returnpattern. - Eliminate unnecessary
elseclauses.
- Use global error boundaries to catch and display unexpected errors gracefully.
- Log errors in production using a service like Sentry or Expo's error reporting tools.
- Validate user inputs at both UI and API levels:
- Use runtime validation libraries for form inputs.
- Sanitize inputs to prevent injection attacks.
- Provide clear, user-friendly error messages for all failure cases.
- Write unit tests for components and utilities using Jest and React Native Testing Library.
- Implement integration tests for critical user flows using Detox or similar tools.
- Use Expo's testing utilities to run tests in iOS and Android environments.
- Consider snapshot testing for UI components to detect unintended changes.
- Aim for at least 80% test coverage for critical paths.
- Mock external dependencies (e.g., APIs, device features) to ensure reliable tests.
- Sanitize all user inputs to prevent XSS and injection attacks.
- Store sensitive data (e.g., tokens, credentials) securely using
react-native-encrypted-storageor Expo's secure storage. - Use HTTPS for all API communications and enforce proper authentication (e.g., OAuth, JWT).
- Follow Expo's security guidelines: https://docs.expo.dev/guides/security/
- Regularly audit dependencies for vulnerabilities using
expo doctorornpm audit.
- Support multiple languages using
expo-localizationor a similar library. - Implement RTL (right-to-left) layouts for languages like Arabic and Hebrew.
- Ensure text scaling and font adjustments for accessibility.
- Use translation keys (e.g.,
t('welcome_message')) instead of hardcoded strings. - Test i18n features in different locales during QA.
- Enable web support for all Expo and React Native projects by default.
- When initializing a project with
expo init, include the--template blankoption and ensurewebis listed as a supported platform inapp.json:{ "expo": { "platforms": ["ios", "android", "web"] } } - Install necessary web dependencies:
react-native-webreact-dom@expo/webpack-config
- Configure
metro.config.jsto support web extensions (e.g.,.web.tsx,.web.ts):module.exports = { resolver: { sourceExts: ['web.tsx', 'web.ts', 'tsx', 'ts', 'js'] } };
- Use
Platform.OSchecks to handle platform-specific logic for web:import { Platform } from 'react-native'; const styles = StyleSheet.create({ container: { padding: Platform.OS === 'web' ? 20 : 10 } });
- Test web builds locally using
expo start --weband ensure compatibility with modern browsers (Chrome, Firefox, Safari). - Include web-specific configurations in the
Checklist for New Projects(see below).
- Use Expo's managed workflow for streamlined development and deployment.
- Prioritize Mobile Web Vitals:
- Optimize load time (aim for <3 seconds).
- Minimize jank (maintain 60 FPS).
- Ensure responsiveness (handle touch events in <100ms).
- Manage environment variables with
expo-constants. - Handle device permissions gracefully using
expo-permissions. - Implement over-the-air (OTA) updates with
expo-updates. - Follow Expo's best practices for app publishing: https://docs.expo.dev/distribution/introduction/
- Test extensively on both iOS, Android, and web to ensure cross-platform compatibility.
- Maintain a consistent project structure to simplify debugging.
- Use TypeScript's strict mode to catch type-related errors early.
- Log errors and performance metrics in development and production.
- Document common issues and resolutions in a
TROUBLESHOOTING.mdfile. - Use Expo's CLI tools (
expo doctor,expo start) to diagnose configuration issues. - Avoid common pitfalls:
- Do not use deprecated APIs or libraries.
- Avoid inline styles for maintainability.
- Do not ignore TypeScript or ESLint warnings.
- Do not create nested projects: Always verify the project root before scaffolding.
- Regularly update dependencies to avoid compatibility issues.
- Maintain a
README.mdwith setup instructions, project overview, and key scripts. - Document custom components, hooks, and utilities with JSDoc or TypeScript comments.
- Reference Expo's official documentation for setup and best practices: https://docs.expo.dev/
- Include a
CHANGELOG.mdto track updates and breaking changes.
- Editor: VS Code with ESLint, Prettier, and TypeScript extensions.
- Linting: ESLint with React Native and TypeScript plugins.
- Formatting: Prettier with default settings.
- Debugging: React Native Debugger, Expo DevTools, or Flipper.
- Version Control: Git with a
.gitignoretailored for Expo projects. - CI/CD: Use GitHub Actions or similar for automated testing and deployment.
- Initialize the project with
expo init --template blankand verifywebis included inapp.jsonplatforms. - Configure
tsconfig.jsonwith strict mode and React Native settings. - Set up ESLint and Prettier with recommended rules.
- Create a consistent folder structure (e.g.,
components/,screens/,utils/). - Implement a theme file for colors, typography, and spacing.
- Set up error boundaries and logging for production.
- Configure OTA updates with
expo-updates. - Install web dependencies (
react-native-web,react-dom,@expo/webpack-config) and configuremetro.config.jsfor web support. - Test on iOS, Android, and web (using
expo start --web) before development begins. - Verify the project root to prevent creating nested projects.