📅 Day 5
💡 tip

AI-Assisted Coding: CLAUDE.md and Cursor Rules

Supercharge your AI-assisted development with proper configuration files

CursorClaudeAI

Welcome to Day 5 of the React Native Advent Calendar!

Today we’re diving into AI-assisted development! Whether you’re using Claude Code, Cursor, or other AI coding assistants, proper configuration can make the difference between generic suggestions and truly helpful, context-aware assistance. We’ll cover CLAUDE.md files, Cursor Rules, and the powerful Expo MCP server that teaches AI about your Expo project!


Why Configuration Matters for AI Coding

AI coding assistants are incredibly powerful, but they need context about your project to provide truly helpful suggestions. Without proper configuration, AI might:

  • ❌ Suggest outdated patterns or deprecated APIs
  • ❌ Use the wrong libraries or incompatible versions
  • ❌ Miss project-specific conventions and architecture decisions
  • ❌ Generate code that doesn’t match your style guide

With proper configuration, AI becomes your context-aware pair programmer that:

  • ✅ Understands your project structure and conventions
  • ✅ Suggests compatible packages and correct versions
  • ✅ Follows your coding style and best practices
  • ✅ Knows about Expo Router patterns and SDK features
  • ✅ Can interact with your development environment

Let’s set this up!


CLAUDE.md: Your Project Context File

The CLAUDE.md file is a project documentation file that provides AI assistants (especially Claude Code) with essential context about your project. Think of it as a README specifically for AI.

Creating Your CLAUDE.md

Place this file in your project root:

# Project Context for AI Assistants

## Project Overview

This is a React Native mobile application built with Expo and Expo Router. The app provides [brief description of your app's purpose].

## Tech Stack

- **Framework**: React Native with Expo SDK 54+
- **Routing**: Expo Router (file-based routing)
- **Language**: TypeScript (strict mode enabled)
- **State Management**: Zustand / React Query / Context API
- **Styling**: Tailwind CSS (via NativeWind) / StyleSheet
- **Backend**: Expo API Routes / Supabase / Firebase
- **Authentication**: Expo Auth Session / Clerk

## Project Structure

app/ # Expo Router screens and layouts
(tabs)/ # Tab navigation group
(auth)/ # Authentication screens
api/ # API routes (server-side)
_layout.tsx # Root layout
components/ # Reusable UI components
ui/ # Base UI components
features/ # Feature-specific components
hooks/ # Custom React hooks
lib/ # Third-party integrations
store/ # Global state management
utils/ # Helper functions and utilities
constants/ # App constants and configuration
types/ # TypeScript type definitions

## Coding Conventions

### File Naming

- Components: PascalCase (e.g., `UserProfile.tsx`)
- Hooks: camelCase with 'use' prefix (e.g., `useAuth.ts`)
- Utilities: camelCase (e.g., `formatDate.ts`)
- Screens: Use Expo Router conventions (e.g., `[id].tsx`, `_layout.tsx`)

### Code Style

- Use functional components with TypeScript
- Prefer named exports over default exports (except for Expo Router screens)
- Use const assertions for constants
- Async/await over Promises
- Early returns over nested conditionals

### Component Structure

```tsx
// 1. Imports (external libraries first, then internal)
import { View, Text } from 'react-native';
import { useState } from 'react';

import { Button } from '@/components/ui';
import { useAuth } from '@/hooks';

// 2. Types/Interfaces
interface UserProfileProps {
	userId: string;
}

// 3. Component
export function UserProfile({ userId }: UserProfileProps) {
	// Hooks
	const { user } = useAuth();
	const [isLoading, setIsLoading] = useState(false);

	// Event handlers
	const handlePress = () => {
		// Implementation
	};

	// Render
	return (
		<View>
			<Text>{user?.name}</Text>
			<Button onPress={handlePress}>Action</Button>
		</View>
	);
}
```

## Expo Router Patterns

### Navigation

- Use `router.push()` for stack navigation
- Use `router.replace()` to replace the current screen
- Use `Link` component for declarative navigation
- Use `useLocalSearchParams()` to access route parameters

### File-Based Routing

- `index.tsx` = default route in a directory
- `[id].tsx` = dynamic route segment
- `(group)/` = layout group (doesn't affect URL)
- `_layout.tsx` = layout component for the directory

### Protected Routes

```tsx
<Stack.Protected guard={isLoggedIn}>
	<Stack.Screen name="dashboard" />
</Stack.Protected>
```

## API Routes

API routes live in `app/api/` and use the `+api.ts` suffix:

```tsx
// app/api/users+api.ts
export function GET(request: Request) {
	return Response.json({ users: [] });
}

export async function POST(request: Request) {
	const body = await request.json();
	return Response.json({ success: true }, { status: 201 });
}
```

## State Management

- Use Zustand for global app state
- Use React Query for server state
- Use Context API for component tree state
- Prefer local state when possible

## Testing

- Use `@testing-library/react-native` for component tests
- Place tests next to the files they test (e.g., `Button.test.tsx`)
- Use `jest.mock()` for mocking dependencies

## Dependencies

### Installing New Packages

**Always use `npx expo install [package]`** instead of npm/yarn directly. This ensures compatibility with your Expo SDK version.

```bash
# Good
npx expo install react-native-reanimated

# Avoid
npm install react-native-reanimated
```

### Common Libraries

- UI: `@shopify/flash-list`, `react-native-reanimated`, `react-native-gesture-handler`
- Forms: `react-hook-form`, `zod`
- Data: `@tanstack/react-query`, `axios`
- Storage: `expo-secure-store`, `@react-native-async-storage/async-storage`

## Environment Variables

- Store sensitive data in `.env.local` (gitignored)
- Use `process.env.EXPO_PUBLIC_*` for client-side variables
- Use `process.env.*` (without EXPO*PUBLIC*) for server-side only

## Common Commands

```bash
# Development
npx expo start                 # Start dev server
npx expo start --tunnel        # Start with tunnel (for testing on real devices)

# Building
npx expo run:ios              # Build and run on iOS simulator
npx expo run:android          # Build and run on Android emulator

# Production builds
eas build --platform ios      # Build for iOS
eas build --platform android  # Build for Android

# Testing
npm test                      # Run tests
npm run type-check           # TypeScript check
npm run lint                 # Lint code
```

## Important Notes for AI

1. **Always check Expo SDK compatibility** before suggesting packages
2. **Use Expo Router navigation** instead of React Navigation directly
3. **Prefer Expo modules** (expo-*) over bare React Native modules when available
4. **Remember this is a mobile app** - consider platform differences (iOS/Android)
5. **Use TypeScript strictly** - no `any` types unless absolutely necessary
6. **Consider performance** - mobile devices have limited resources

## Recent Architectural Decisions

[Document major decisions here, e.g.:]

- Chose Zustand over Redux for simpler state management (2025-12-01)
- Using NativeWind for styling to share CSS knowledge with web team (2025-12-01)
- Implemented API routes for sensitive operations vs. client-side API calls (2025-12-01)

## Known Issues & Workarounds

[Document any quirks or workarounds here]

- Issue with `expo-image` on Android 12: Use fallback to `Image` component
- React Query cache persists between dev reloads: Clear cache in dev mode

---

Last updated: 2025-12-05

Key Sections to Include

  1. Tech Stack: What frameworks, libraries, and tools you’re using
  2. Project Structure: How your codebase is organized
  3. Coding Conventions: Your style guide and best practices
  4. Common Patterns: Expo Router patterns, API routes, etc.
  5. Dependencies: How to install packages (use npx expo install!)
  6. Commands: Frequently used commands
  7. Important Notes: Anything AI should always remember

Pro tip: Keep your CLAUDE.md updated as your project evolves. It’s worth the investment!


Cursor Rules: Configuration for Cursor AI

If you’re using Cursor AI, create a .cursorrules file in your project root. This provides similar context but in Cursor’s format:

# Expo + React Native + TypeScript Project

You are an expert in React Native, Expo, TypeScript, and mobile app development.

## Key Principles

- Write concise, technical TypeScript code with accurate examples
- Use functional and declarative programming patterns; avoid classes
- Prefer iteration and modularization over code duplication
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
- Structure files: imports, types, component, helpers, static content, exports

## Tech Stack

- React Native with Expo SDK 54+
- Expo Router for file-based routing
- TypeScript (strict mode)
- NativeWind / StyleSheet for styling
- Zustand / React Query for state management

## React Native / Expo Best Practices

### File-Based Routing with Expo Router

- Use file-based routing in the `app/` directory
- Dynamic routes: `[id].tsx`
- Layout groups: `(tabs)/`, `(auth)/`
- Layouts: `_layout.tsx`
- API routes: `+api.ts` suffix

### Navigation

```tsx
import { router, Link, useLocalSearchParams } from 'expo-router';

// Programmatic navigation
router.push('/profile/123');
router.replace('/login');

// Declarative navigation
<Link href="/profile/123">View Profile</Link>;

// Access params
const { id } = useLocalSearchParams();
```

### Components

- Use functional components with TypeScript
- Prefer named exports (except for Expo Router screens)
- Use `View`, `Text`, `Pressable` from `react-native`
- Import platform-specific code with `.ios.tsx` / `.android.tsx` extensions

### Styling

```tsx
// Using StyleSheet
import { StyleSheet, View } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
});

// Or using NativeWind (Tailwind)
<View className="flex-1 p-4">
```

### State Management

- Use `useState` for local state
- Use Zustand for global state
- Use React Query for server state
- Avoid prop drilling - use Context or Zustand

### Performance

- Use `FlashList` instead of `FlatList` for long lists
- Memoize expensive calculations with `useMemo`
- Memoize callbacks with `useCallback`
- Use `React.memo` for pure components
- Lazy load screens with `React.lazy` (when not using Expo Router)

### Platform-Specific Code

```tsx
import { Platform } from 'react-native';

// Inline platform check
const padding = Platform.OS === 'ios' ? 20 : 10;

// Platform.select
const styles = StyleSheet.create({
	container: {
		...Platform.select({
			ios: { paddingTop: 20 },
			android: { paddingTop: 10 }
		})
	}
});

// Separate files
// Button.ios.tsx
// Button.android.tsx
```

## TypeScript Best Practices

- Use strict mode
- Avoid `any` - use `unknown` if type is truly unknown
- Define interfaces for component props
- Use type inference where possible
- Use const assertions for constants

```tsx
// Good
interface ButtonProps {
	title: string;
	onPress: () => void;
	variant?: 'primary' | 'secondary';
}

export function Button({ title, onPress, variant = 'primary' }: ButtonProps) {
	// Implementation
}

// Const assertion
const colors = {
	primary: '#007AFF',
	secondary: '#5856D6'
} as const;
```

## Expo Specific

### Installing Dependencies

**ALWAYS use `npx expo install` instead of npm/yarn:**

```bash
npx expo install react-native-reanimated
npx expo install expo-image
```

This ensures SDK compatibility.

### Environment Variables

```bash
# .env.local
EXPO_PUBLIC_API_URL=https://api.example.com  # Available on client
EXPO_PUBLIC_API_KEY=abc123                   # Available on client
SECRET_KEY=secret123                          # Server-side only
```

```tsx
// Usage
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
```

### Common Expo Modules

- `expo-router` - File-based routing
- `expo-image` - Optimized images
- `expo-font` - Custom fonts
- `expo-secure-store` - Secure storage
- `expo-camera` - Camera access
- `expo-location` - Location services
- `expo-notifications` - Push notifications

### API Routes

```tsx
// app/api/users+api.ts
export async function GET(request: Request) {
	const users = await db.users.findMany();
	return Response.json(users);
}

export async function POST(request: Request) {
	const body = await request.json();
	const user = await db.users.create(body);
	return Response.json(user, { status: 201 });
}
```

## Error Handling

```tsx
try {
	const result = await fetchData();
} catch (error) {
	if (error instanceof Error) {
		console.error('Error:', error.message);
	}
	// Handle error appropriately
}
```

## Testing

```tsx
import { render, fireEvent } from '@testing-library/react-native';

describe('Button', () => {
	it('calls onPress when pressed', () => {
		const onPress = jest.fn();
		const { getByText } = render(<Button title="Press me" onPress={onPress} />);

		fireEvent.press(getByText('Press me'));
		expect(onPress).toHaveBeenCalledTimes(1);
	});
});
```

## Important Reminders

1. This is a mobile app - consider iOS and Android differences
2. Always use `npx expo install` for dependencies
3. Use Expo Router patterns, not React Navigation directly
4. Consider performance on mobile devices
5. Test on both iOS and Android
6. Use TypeScript strictly - avoid `any`
7. Follow React Native best practices (avoid web patterns that don't translate)

## Code Generation Rules

- When generating navigation code, use Expo Router APIs
- When suggesting packages, verify Expo SDK compatibility
- When creating layouts, remember mobile constraints (smaller screens)
- When handling user input, consider mobile keyboards and gestures
- When dealing with images, use `expo-image` over `Image`
- When implementing forms, consider mobile UX (large touch targets, clear error states)

Using Cursor Rules

  1. Save as .cursorrules in your project root
  2. Cursor will automatically read this file
  3. AI suggestions will follow these guidelines
  4. Update as your project conventions evolve

Pro tip: Combine .cursorrules with CLAUDE.md for maximum AI assistance across different tools!


Wrapping Up

That’s it for Day 5 of the React Native Advent Calendar!

AI-assisted coding is incredibly powerful, but it’s only as good as the context you provide. With CLAUDE.md, .cursorrules, and also the new Expo MCP server, you’re giving your AI assistant everything it needs to be a true pair programmer!

Key Takeaways

  1. CLAUDE.md provides project context for AI assistants
  2. .cursorrules configures Cursor-specific behavior
  3. Expo MCP server teaches AI about Expo SDK and enables automation
  4. Proper configuration transforms AI from generic helper to context-aware expert

What to explore next:

Download Templates

You can copy the CLAUDE.md and .cursorrules templates from this article and customize them for your project!

Ready to supercharge your AI-assisted development? Let me know your results on Twitter!

Tomorrow we’ll explore Day 6’s topic - see you then! 🎄