Expo SDK
Overview
Expo SDK 54+ provides a managed React Native development environment with file-based routing (Expo Router), native module access, and streamlined build tooling. This skill covers app configuration, the root layout provider pattern, and key Expo/RN libraries.
Prerequisite :
or Expo SDK 54+ in
Workflows
Setting up a new Expo demo:
Create project: npx create-expo-app [demo-name] --template blank-typescript
Install core dependencies: pnpm add expo-router expo-image expo-haptics react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet @shopify/flash-list lucide-react-native nativewind tailwindcss@3
Configure NativeWind (see skill)
Set up root layout with provider stack
Configure with scheme, name, splash
Add route groups and screens
Run: (Expo dev server)
Adding a new library:
Install with pnpm:
Check if Expo config plugin needed in
Rebuild dev client if native module added:
Guidance
app.json Configuration
Key fields for demo apps:
Field Purpose Display name URL-safe identifier Deep link scheme (e.g., ) (default for demos) Splash screen configuration expo.ios.bundleIdentifier iOS bundle ID Android package name Expo config plugins (e.g., )
Root Layout Provider Pattern
The root
wraps the entire app with providers. Standard order:
GestureHandlerRootView (flex: 1)
└── SafeAreaProvider
└── ThemeProvider / Context
└── Stack (Expo Router)
must be outermost (required by gesture handler and bottom sheets)
provides safe area insets to all descendants
App-level context providers go between SafeAreaProvider and Stack
<Stack screenOptions={{ headerShown: false }} /> for custom headers
expo-image (replaces RN Image)
Use
for all image rendering — provides caching, blurhash placeholders, content-fit modes, and animated transitions.
Key props:
— URI string or require() for local images
— blurhash string for loading state
— | |
— fade-in duration in ms (e.g., )
expo-haptics
Provide tactile feedback on interactions:
— light tap for selections, toggles
Haptics.impactAsync(ImpactFeedbackStyle.Medium) — button press, card tap
Haptics.notificationAsync(NotificationFeedbackType.Success) — action completion
Use sparingly — haptics on every touch is annoying.
Safe Area Insets
Account for device notch, status bar, and home indicator:
— returns { top, bottom, left, right } in points
Apply to screen containers:
NativeWind classes: use or wrap in SafeAreaView
@gorhom/bottom-sheet
Replaces Radix Dialog for mobile modal patterns:
Use for detail views, selections, filters, forms
Define snap points: snapPoints={['25%', '50%', '90%']}
Backdrop: with press-to-dismiss
for scrollable content inside sheets
Requires as ancestor
FlashList (replaces FlatList)
High-performance list rendering from
:
Drop-in FlatList replacement with mandatory prop
— estimated height of each item in points
Recycling architecture for smooth 60fps scrolling
Use contentContainerClassName for NativeWind styling
lucide-react-native
Icon library for React Native (matches web lucide-react):
Import individual icons: import { Home, Settings, ChevronRight } from 'lucide-react-native'
Props: , ,
Consistent icon set across mobile and web codebases
StatusBar
Configure status bar appearance per screen:
<StatusBar style="dark" /> for light backgrounds
<StatusBar style="light" /> for dark backgrounds
Import from
Best Practices
Wrap root layout in with
Use expo-image for all images (caching, blurhash, performance)
Add haptics to primary actions only (buttons, major selections) — not every touch
Set on all FlashList components
Place providers in root , not in individual screens
Use for manual padding, for simple wrapping
Test on real device for haptics and performance verification
Anti-Patterns
Using React Native instead of
Using for large datasets instead of
Forgetting (causes bottom sheet and gesture crashes)
Overusing haptics on every interaction
Hardcoding status bar height instead of using safe area insets
Missing on FlashList (required prop, console warning)
Placing inside ScrollView (causes layout issues)
Not including plugin in plugins array