Skip to content

Instantly share code, notes, and snippets.

@Kudo
Last active September 30, 2025 12:17
Show Gist options
  • Select an option

  • Save Kudo/cbf55e9895fabde19ed440ac5f626a76 to your computer and use it in GitHub Desktop.

Select an option

Save Kudo/cbf55e9895fabde19ed440ac5f626a76 to your computer and use it in GitHub Desktop.
Expo agentic onboarding context

Expo Router Quick Onboarding Guide

What is Expo Router?

File-based router for React Native and web applications built on React Navigation. Automatic deep linking, universal navigation across platforms.

Core Concepts

File Structure Rules

  • All routes live in app/ directory
  • Each file = a screen/page with automatic URL
  • app/index.tsx = initial route (/)
  • app/_layout.tsx = root layout (replaces App.tsx)
  • Non-navigation code goes outside app/

File Naming Convention

  • home.tsx/home (static route)
  • [id].tsx/123 (dynamic route)
  • (tabs)/ → route group (doesn't affect URL)
  • index.tsx → default route for directory
  • _layout.tsx → navigation layout
  • +not-found.tsx → catch-all error page

Navigation

Imperative Navigation

import { useRouter } from 'expo-router';

const router = useRouter();
router.navigate('/about');      // Navigate to route
router.push('/about');          // Push onto stack
router.back();                  // Go back
router.replace('/about');       // Replace current

Declarative Navigation

import { Link } from 'expo-router';

<Link href="/about">About</Link>
<Link href="/user/123">User Profile</Link>

// With params
<Link href={{
  pathname: '/user/[id]',
  params: { id: '123' }
}}>Profile</Link>

// Pressable links
<Link href="/about" asChild>
  <Pressable><Text>About</Text></Pressable>
</Link>

Dynamic Routes & Params

// File: app/user/[id].tsx
import { useLocalSearchParams } from 'expo-router';

export default function User() {
  const { id } = useLocalSearchParams();
  return <Text>User ID: {id}</Text>;
}

Layouts

Root Layout (app/_layout.tsx)

import { Stack } from 'expo-router';
import { useFonts } from 'expo-font';

export default function RootLayout() {
  const [loaded] = useFonts({ /* fonts */ });

  if (!loaded) return null;

  return <Stack />;
}

Stack Layout

import { Stack } from 'expo-router';

export default function Layout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Home' }} />
      <Stack.Screen name="about" options={{ headerShown: false }} />
    </Stack>
  );
}

Tab Layout

import { Tabs } from 'expo-router';
import { FontAwesome } from '@expo/vector-icons';

export default function TabLayout() {
  return (
    <Tabs screenOptions={{ tabBarActiveTintColor: 'blue' }}>
      <Tabs.Screen
        name="index"
        options={{
          title: 'Home',
          tabBarIcon: ({ color }) =>
            <FontAwesome size={28} name="home" color={color} />
        }}
      />
      <Tabs.Screen name="settings" options={{ title: 'Settings' }} />
    </Tabs>
  );
}

Slot Layout (No Navigator)

import { Slot } from 'expo-router';

export default function Layout() {
  return (
    <>
      <Header />
      <Slot />
      <Footer />
    </>
  );
}

Common Patterns

Tabs with Stack

app/
  _layout.tsx           # Root stack
  (tabs)/
    _layout.tsx         # Tab navigator
    index.tsx           # Home tab
    profile.tsx         # Profile tab
  modal.tsx             # Modal over tabs

Authentication Flow

// app/_layout.tsx
export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="login" options={{ presentation: 'modal' }} />
    </Stack>
  );
}

Protected Routes

import { Redirect } from 'expo-router';

export default function ProtectedPage() {
  const { user } = useAuth();

  if (!user) {
    return <Redirect href="/login" />;
  }

  return <Text>Protected Content</Text>;
}

Tips

  • Use router.navigate() for most navigation
  • Relative paths: ./page (current dir), ../page (parent dir)
  • Query params: href="/users?limit=20" or router.setParams({ limit: 20 })
  • Deep links work automatically: myapp://profile/123
  • Set initialRouteName in layouts for proper back navigation
  • Use <Link prefetch /> for faster navigation
  • Hide tabs: <Tabs.Screen options={{ href: null }} />

Example App Structure

app/
  _layout.tsx           # Root layout
  index.tsx             # Home page (/)
  about.tsx             # About page (/about)
  (tabs)/
    _layout.tsx         # Tab layout
    index.tsx           # Home tab (/)
    profile.tsx         # Profile tab (/profile)
  user/
    [id].tsx            # Dynamic user page (/user/123)
  +not-found.tsx        # 404 page

Ready to build! 🚀

Project Overview

This is an Expo/React Native mobile application. Prioritize mobile-first patterns, performance, and cross-platform compatibility.

Essential Commands

Development

npx expo start                  # Start dev server
npx expo start --clear          # Clear cache and start dev server
npx expo install <package>      # Install packages with compatible versions
npx expo install --check        # Check which installed packages need to be updated
npx expo install --fix          # Automatically update any invalid package versions

Building & Testing

npx expo prebuild               # Generate native projects
npx expo run:ios                # Build and run on iOS device
npx expo run:android            # Build and run on Android device
npx expo doctor                 # Check project health and dependencies
npm expo lint                   # Run ESLint

Production

npx eas-cli@latest build --platform ios -s            # Use EAS to build for iOS platform and submit to App Store
npx eas-cli@latest build --platform android -s        # Use EAS to build for Android platform and submit to Google Play Store
npx expo export -p web && npx eas-cli@latest deploy   # Deploy web to EAS Hosting

Development Principles

Code Style & Standards

  • TypeScript First: Use TypeScript for all new code with strict type checking
  • Naming Conventions: Use meaningful, descriptive names for variables, functions, and components
  • Self-Documenting Code: Write clear, readable code that explains itself; only add comments for complex business logic or design decisions
  • React 19 Patterns: Follow modern React patterns including:
    • Function components with hooks
    • Enable React Compiler
    • Proper dependency arrays in useEffect
    • Memoization when appropriate (useMemo, useCallback)
    • Error boundaries for better error handling

Architecture & Best Practices

Recommended Libraries

  • Navigation: expo-router for navigation
  • Images: expo-image for optimized image handling and caching
  • Animations: react-native-reanimated for performant animations on native thread
  • Gestures: react-native-gesture-handler for native gesture recognition
  • Storage: Use expo-sqlite for persistent storage, expo-sqlite/kv-store for simple key-value storage

Debugging & Development Tools

DevTools Integration

  • React Native DevTools: Use MCP open_devtools command to launch debugging tools
  • Network Inspection: Monitor API calls and network requests in DevTools
  • Element Inspector: Debug component hierarchy and styles
  • Performance Profiler: Identify performance bottlenecks
  • Logging: Use console.log for debugging (remove before production), console.warn for deprecation notices, console.error for actual errors, and implement error boundaries for production error handling

Testing & Quality Assurance

Automated Testing with MCP Tools

  • Component Testing: Add testID props to components for automation
  • Visual Testing: Use MCP automation_take_screenshot to verify UI appearance
  • Interaction Testing: Use MCP automation_tap_by_testid to simulate user interactions
  • View Verification: Use MCP automation_find_view_by_testid to validate component rendering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment