Using Expo vs React Native CLI
1. Understanding Expo Managed Workflow
The Expo Managed Workflow is a streamlined approach to building React Native applications that abstracts away much of the native code complexity. It allows developers to build, deploy, and manage apps using only JavaScript/TypeScript and a minimal amount of native configuration.
| Feature | Description | Status |
|---|---|---|
| Native Code Abstraction | Expo handles native code and dependencies, reducing boilerplate. | NEW |
| Prebuilt Modules | Access to a wide range of pre-built modules (camera, location, etc.) | NEW |
| Deployment | Deploy directly to app stores via Expo services or EAS Build. | NEW |
| Development Environment | Uses Expo Go app for live reload and debugging. | NEW |
Example: Setting up an Expo Project
npm install -g @expo/cli
expo init MyExpoApp
cd MyExpoApp
expo start
Key Benefits of Expo Managed Workflow
- Fast iteration with live reload
- Reduced boilerplate and configuration
- Access to Expo SDK features without native setup
- Easy deployment with EAS Build or Expo Publish
2. Understanding Bare Workflow
The Bare Workflow in React Native provides direct access to the native platform APIs without the abstraction layer of Expo. It's ideal for developers who need fine-grained control over their app's native functionality.
| Aspect | Description | Notes |
|---|---|---|
| Native Modules | Direct access to native iOS and Android modules | Requires knowledge of platform-specific code |
| Device APIs | Full access to device capabilities (camera, GPS, etc.) | May require additional setup and permissions |
| Build Process | Uses Xcode and Android Studio directly | More complex setup compared to Expo |
| Deployment | Manual configuration for app stores | Requires handling of certificates and provisioning profiles |
Example: Bare Workflow Project Structure
my-bare-app/
├── android/
│ ├── app/
│ └── build.gradle
├── ios/
│ ├── MyBareApp.xcodeproj
│ └── AppDelegate.m
├── src/
│ └── App.js
├── package.json
└── babel.config.js
3. Using Expo CLI
Expo CLI is a command-line tool that helps you create, build, and manage React Native projects with Expo. It simplifies development by providing a managed workflow that includes pre-built features and tools.
| Command | Description | Usage |
|---|---|---|
| expo init | Creates a new Expo project | expo init MyApp |
| expo start | Starts the development server | expo start |
| expo run:ios | Runs the project on iOS simulator | expo run:ios |
| expo run:android | Runs the project on Android emulator | expo run:android |
| expo build:ios | Builds the iOS app for distribution | expo build:ios |
| expo build:android | Builds the Android app for distribution | expo build:android |
4. Ejecting from Expo
Expo provides a streamlined development experience, but sometimes you may need to eject to gain access to native modules or customize the build process. Ejecting from Expo allows you to use React Native CLI and native Android/iOS toolchains.
| Step | Description | Action |
|---|---|---|
| 1 | Ensure your project is in a clean state | Run git status and commit any changes to avoid losing work. |
| 2 | Run the eject command | Execute npx expo eject in your project directory. |
| 3 | Choose Eject Mode | Select between managed or bare mode. |
| 4 | Review generated files | Check for updated android/ and ios/ directories. |
| 5 | Update dependencies | Install any missing native dependencies using npx pod install for iOS. |
Post-Eject Considerations
- Native modules must be installed manually via
npm installoryarn add. - Builds must be managed through Xcode (iOS) or Android Studio (Android).
- Expo SDK features become unavailable and must be replaced with native or community alternatives.
5. Using Expo Go App
The Expo Go app is a mobile client that allows you to run Expo projects directly on your iOS or Android device. It's particularly useful for development and testing without needing to build native binaries.
| Feature | Description | Availability |
|---|---|---|
| Expo Go | Mobile app for running Expo projects | Available on iOS and Android |
| Live Reload | Automatically updates the app when code changes are saved | Yes, built-in |
| Development Server | Hosts the development server for local projects | Yes, via LAN or tunnel |
Example: Running an Expo Project on Device
expo start
Scan the QR code with your device's camera to open the project in Expo Go.
6. Configuring app.json
| Property | Values | Description |
|---|---|---|
| expo | {...} |
Expo-specific configuration options |
| name | string |
Display name of the app |
| slug | string |
Unique identifier for the app on Expo |
| version | string |
App version (e.g., "1.0.0") |
| platforms | array |
Supported platforms (e.g., ["ios", "android"]) |
| icon | string |
Path to app icon (PNG or JPG) |
| splash | {...} |
Splash screen configuration |
| ios | {...} |
iOS-specific configuration (e.g., bundleIdentifier, buildNumber) |
| android | {...} |
Android-specific configuration (e.g., package, versionCode) |
| web | {...} |
Web-specific configuration (e.g., output, favicon) |
Example: Basic app.json structure
{
"expo": {
"name": "MyApp",
"slug": "my-app",
"version": "1.0.0",
"platforms": ["ios", "android"],
"icon": "./assets/icon.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"buildNumber": "1",
"bundleIdentifier": "com.myapp"
},
"android": {
"package": "com.myapp",
"versionCode": 1
},
"web": {
"output": "web",
"favicon": "./assets/favicon.png"
}
}
}
7. Using Expo SDK Features
Expo provides a rich set of SDK features that simplify development in React Native. These features are accessible through the expo package and include utilities for device APIs, UI components, and more.
| Feature | Description | Usage Example | Notes |
|---|---|---|---|
| expo-constants | Provides access to app and device information. | import Constants from 'expo-constants';\n\nconsole.log(Constants.appVersion); |
Useful for versioning and debugging. |
| expo-filesystem | Provides access to the device's file system. | import * as FileSystem from 'expo-file-system';\n\nconst fileUri = await FileSystem.documentDirectory + 'example.txt'; |
Supports read/write operations. |
| expo-secure-store | Securely stores key-value pairs on the device. | import * as SecureStore from 'expo-secure-store';\n\nawait SecureStore.setItemAsync('key', 'value'); |
Recommended for sensitive data. |
| expo-camera | Provides camera functionality with preview and capture. | import { Camera } from 'expo-camera';\n\nconst [permission] = await Camera.requestCameraPermissionsAsync(); |
Requires runtime permissions. |
| expo-notifications | Handles local and push notifications. | import * as Notifications from 'expo-notifications';\n\nNotifications.scheduleNotificationAsync({\n content: { title: 'Hello', body: 'This is a notification' },\n trigger: null,\n}); |
Supports scheduling and delivery. |
expo build. They are not accessible in a standard React Native CLI project unless manually integrated.8. Handling Native Code
| Platform | Native Code Type | Description | Integration Method |
|---|---|---|---|
| iOS | Swift / Objective-C |
Native iOS development language | Use React Native Bridging to integrate Swift/Objective-C code with JavaScript |
| Android | Kotlin / Java |
Native Android development language | Use React Native Bridging to integrate Kotlin/Java code with JavaScript |
Example: Adding a Native Module
// Example of a native module in React Native
import { NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
// Usage in JavaScript
MyNativeModule.someMethod("parameter");
Example: iOS Native Module Integration
// Swift implementation in iOS
@objc(MyNativeModule)
class MyNativeModule: NSObject {
@objc
func someMethod(_ parameter: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
// Implementation logic here
resolve("Result from native code")
}
}
Example: Android Native Module Integration
// Java implementation in Android
@ReactModule(name = "MyNativeModule")
public class MyNativeModule extends ReactContextBaseJavaModule {
@ReactMethod
public void someMethod(String parameter, Promise promise) {
// Implementation logic here
promise.resolve("Result from native code");
}
}
Native Code Handling Strategies
- Bridging: Use React Native's bridging to connect native modules with JavaScript
- Platform-specific APIs: Access platform-specific features using native code
- Module Registration: Ensure proper registration of native modules in the React Native context
9. Comparing Build Processes
| Aspect | Expo | React Native CLI |
|---|---|---|
| Build Environment | Cloud-based builds via Expo Build Service | Local machine or CI/CD server |
| Native Code Integration | Limited; uses Expo SDK | Full control over native modules |
| Configuration | Managed via app.json or app.config.js |
Manual configuration in android/ and ios/ folders |
| Deployment | Push updates via expo publish |
Requires submitting to app stores |
| Build Time | Fast, typically under 5 minutes | Can take several minutes depending on project size |
| Platform Support | Supports iOS, Android, Web, and Desktop | Supports iOS and Android only |
Example: Building with React Native CLI
cd android
./gradlew assembleRelease
cd ../ios
xcodebuild -workspace MyProject.xcworkspace -scheme MyProject -configuration Release
10. Choosing the Right Workflow
Expo vs React Native CLI
- Expo: Ideal for rapid prototyping, cross-platform development, and teams wanting to avoid native code setup. Offers a managed workflow with extensive built-in APIs.
- React Native CLI: Best for teams needing full control over native modules, custom native features, or performance optimization. Requires more initial setup and native development knowledge.
| Feature | Expo | React Native CLI |
|---|---|---|
| Workflow Type | Managed | Unimodules / Bare |
| Native Module Support | Limited (via Expo SDK) | Full control |
| Build Time | Slower (managed build) | Faster (custom build) |
| App Size | Larger (includes Expo SDK) | Smaller (only needed modules) |
| Development Speed | Fast (no native setup) | Slower (requires setup) |
| Platform Support | Web, iOS, Android | iOS, Android |
When to Use Which
- Choose Expo if:
- You're building a cross-platform app quickly
- You want to avoid native code setup
- You're using many built-in features (camera, location, etc.)
- Choose React Native CLI if:
- You need custom native modules
- Performance is critical
- You're comfortable with native development