Expo CLI Best Practices
A condensed summary of the 25 most important best practices drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important best practices drawn from every page in this section.
Start Metro with npx expo start: Use the Expo CLI entry - raw react-native start skips Expo-specific middleware and doctor integrations.
Default to LAN on shared Wi-Fi: Fastest iteration for phone + laptop on the same network - tunnel adds latency and external dependencies.
Reach for tunnel only when blocked: Corporate VPNs and guest Wi-Fi isolation need --tunnel - document the slower reload expectation for the team.
Use --clear when bundles look stale: Suspect Fast Refresh ghosts or wrong entry files - cache clears are cheaper than hour-long debug rabbit holes.
Standardize npm scripts: start, start:tunnel, ios, android - onboarding should not require memorizing flag combinations.
Open iOS Simulator with i from the terminal: Faster than context-switching to Xcode for daily UI work - keep one simulator booted during feature dev.
Pick a realistic Android API level: Match RN 0.86 guidance (recent API images) - ancient emulators hide edge-to-edge and permission regressions.
Snapshot simulators in CI screenshots: xcrun simctl and adb exec-out screencap - visual regression does not need physical devices for every PR.
Test on a physical device weekly minimum: Simulators miss camera, push, haptics, and performance - USB or internal EAS builds close the gap.
Use expo run:ios --device for native iteration: Development builds on hardware beat Expo Go once custom native code ships.
Pair Android USB with adb reverse when needed: localhost Metro on device workflows need reverse port forwarding - document the command in README.
Adopt expo-dev-client early: Install before the first native module - Expo Go cannot load arbitrary native dependencies.
Start dev client with npx expo start --dev-client: The launcher expects the custom scheme - mixing Expo Go flags causes confusing connection errors.
Rebuild dev client on SDK bumps: OTA cannot change native shells - schedule eas build --profile development in the upgrade checklist.
Register custom dev menu items sparingly: registerDevMenuItems for feature flags and env badges - not ten entries nobody remembers.
Open React Native DevTools with j: Hermes debugging lives in DevTools - remote Chrome debugging is unsupported on modern RN.
Use Components panel for layout bugs: Select-on-device beats console.log layout guesses - inspect props and style arrays live.
Emulate light/dark in DevTools on RN 0.86: Command Palette media emulation catches theme bugs without flipping system settings constantly.
Treat Flipper as legacy: Default to DevTools + platform IDEs - do not add Flipper to greenfield Expo SDK 57 apps without a concrete gap.
Use Xcode and Android Studio for native crashes: JS DevTools do not replace native stack traces - open the native IDE when the redbox is native-side.
Trust Fast Refresh, not Hot Reload: Hot Reload is gone - if state looks wrong after edit, check mixed default/named exports breaking refresh boundaries.
Mark files // @refresh reset when needed: Stateful modules that must remount should opt out of preservation - document why in the comment.
Expect useEffect to re-run after refresh: Do not fight re-fetch on refresh - idempotent effects or guard with refs when duplication hurts.
Wireless debugging after USB pairing works: Android adb pair / iOS Xcode network pairing - verify once per device, then drop the cable for desk testing.
Internal distribution for QA outside engineering: EAS preview builds for PM and design - Expo Go is not a stand-in for production native behavior.
@refresh reset.r) is the escape hatch - not a daily habit.Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 16, 2026