Expo vs Bare CLI
Choosing between Expo (managed workflow) and the bare React Native CLI. The trade-offs, and a flow to upgrade between them.
React Native — Expo vs CLI
EXAMPLE
# ===== Two front doors ===== # Expo: # - Hides Xcode / Android Studio for the start # - OTA updates via EAS Update # - Pre-built native modules (camera, location, notifications, ...) # - Free + paid services (build, submit, update) # - Best DX for solo + small teams # # React Native CLI (bare): # - You manage Xcode / Android Studio + native code # - Use any native lib # - Custom build configs # - More work, more control # ===== Start with Expo ===== npx create-expo-app my-app cd my-app npx expo start # Scan QR with Expo Go (dev client) — instant on-device preview. # ===== Bare CLI start ===== npx react-native init MyApp cd MyApp npx react-native run-ios npx react-native run-android # Requires Xcode + Android Studio. # ===== Decision tree ===== # Will the app need a NATIVE module not in Expo SDK? # - No -> Expo # - Yes -> Expo (with config plugins / custom dev client) OR bare CLI # # Need custom Android / iOS native code? # - No -> Expo # - Yes -> Expo prebuild OR bare CLI # # Want zero ops + OTA updates? # - Yes -> Expo # - Mostly -> CodePush + bare CLI # ===== Expo with custom native code (the modern path) ===== # 'prebuild' generates the ios/android folders so you can edit native code: npx expo prebuild # After this, you can run via expo OR via Xcode / Android Studio. # config plugins keep your native customisations declarative in app.json. # ===== Migrating Expo -> bare CLI (last resort) ===== npx expo prebuild # generate ios/android # Then commit; treat as bare CLI from here. # You lose OTA-managed services unless you add EAS Update separately. # ===== Build + submit ===== # Expo: eas build + eas submit (cloud builds) # npx eas build -p ios # npx eas submit -p ios # Bare CLI: build via Xcode / Android Studio (or fastlane). # ===== Costs ===== # Expo: free tier generous; paid tiers for build + updates volumes # Bare CLI: 'free' but your time on native config + builds is not # ===== Patterns to internalise ===== # - Default to Expo in 2026 unless you have a SPECIFIC native blocker # - Use prebuild + config plugins to keep native code declarative # - EAS for builds + submits + OTA updates # - Pin Expo SDK versions; major upgrades require care # ===== Pitfalls ===== # - Going bare CLI to 'be safer' and discovering native build pain # - Sticking with Expo Go after needing a custom dev client # - Using libraries without checking Expo support # - Mixing iOS Pod versions with Expo SDK expectations
Why it matters
Default to Expo in 2026. Use prebuild + config plugins when you need native code. Reach for bare CLI only for specific native blockers. The DX gap between Expo and CLI is real; pay for EAS instead of paying yourself in native debugging time.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Expo (recommended for most apps) npx create-expo-app@latest my-app cd my-app && npx expo start # Bare CLI (full native control) npx @react-native-community/cli init MyAppTry it Yourself »
Exercise
Create a new Expo app.
npx create-
-app@latest my-app
Four letters.
Discussion
Loading…