expo-dev-client

star 27

Use when building custom development clients for Expo apps, integrating custom native modules, using Apple ecosystem features, third-party native SDKs, or when Expo Go limitations are encountered

bidah By bidah schedule Updated 3/12/2026

name: expo-dev-client description: Use when building custom development clients for Expo apps, integrating custom native modules, using Apple ecosystem features, third-party native SDKs, or when Expo Go limitations are encountered

Expo Dev Client

Overview

A custom development client is a debug build of your app that includes your specific native modules and configuration. It replaces Expo Go when you need native code that Expo Go does not bundle.

Core principle: Use Expo Go for rapid prototyping. Switch to a dev client when you need custom native code, and use EAS Build to create and distribute it.

When to Use

Use a dev client when your app requires:

  • Custom native modules not included in Expo Go (e.g., Bluetooth, NFC, custom camera pipelines)
  • Apple ecosystem integration (HealthKit, HomeKit, CarPlay, App Clips)
  • Third-party native SDKs (Stripe native, Mapbox, Firebase Analytics with custom config)
  • Custom native configuration (specific entitlements, background modes, custom URL schemes)
  • Config plugins that modify native project files
  • Expo Modules API for writing your own native modules

When NOT to Use

  • App only uses libraries included in Expo Go (check the Expo SDK docs)
  • Quick prototyping or demo purposes (stick with Expo Go)
  • Web-only features

Expo Go vs Dev Client

Feature Expo Go Dev Client
Native code Pre-bundled only Any native module
Setup time Zero Requires build step
OTA updates Yes Yes
Custom config plugins No Yes
App Store distribution No Yes (via TestFlight)
Custom app icon/splash No Yes
Background modes Limited Full control
Fast Refresh Yes Yes

Setup

1. Install the Dev Client Package

npx expo install expo-dev-client

This adds the development client UI (launcher, error overlay, dev menu) to your app.

2. Configure EAS Build

# Install EAS CLI if needed
npm install -g eas-cli

# Initialize EAS in your project
eas build:configure

This creates eas.json:

{
  "cli": {
    "version": ">= 5.0.0"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "simulator": true
      }
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {}
  }
}

3. Build the Dev Client

# iOS Simulator build
eas build --platform ios --profile development

# iOS device build (requires Apple Developer account)
eas build --platform ios --profile development \
  --local  # Optional: build locally instead of EAS servers

# Android build
eas build --platform android --profile development

4. Install and Run

# Install on simulator/emulator (automatic after build)
eas build:run --platform ios

# Or start dev server pointing to the dev client
npx expo start --dev-client

Distribution

Internal Distribution (Testing)

For sharing dev builds with your team:

// eas.json
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    }
  }
}

Register test devices:

# Register iOS devices (creates provisioning profile)
eas device:create

# Build for registered devices
eas build --platform ios --profile development

Team members install via the link provided after build completes.

TestFlight Distribution

For broader beta testing:

// eas.json
{
  "build": {
    "preview": {
      "distribution": "internal",
      "ios": {
        "buildConfiguration": "Release"
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "your@email.com",
        "ascAppId": "1234567890"
      }
    }
  }
}
# Build and submit to TestFlight
eas build --platform ios --profile preview
eas submit --platform ios

Local Builds

Build on your machine instead of EAS cloud servers:

# Requires Xcode / Android Studio installed
eas build --platform ios --profile development --local

# Output: .app (simulator) or .ipa (device)

Advantages of local builds:

  • No queue time
  • Full control over build environment
  • Access to local secrets/certificates
  • No EAS build minutes consumed

Adding Native Modules

With Config Plugins

Most Expo-compatible libraries use config plugins that automatically configure native code:

npx expo install expo-camera
// app.json
{
  "expo": {
    "plugins": [
      [
        "expo-camera",
        {
          "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera"
        }
      ]
    ]
  }
}

Rebuild your dev client after adding plugins:

eas build --platform ios --profile development

Custom Native Modules (Expo Modules API)

# Create a new native module
npx create-expo-module my-native-module --local

This scaffolds:

modules/
  my-native-module/
    android/
      src/main/java/.../MyNativeModule.kt
    ios/
      MyNativeModule.swift
    src/
      index.ts          # TypeScript API
    expo-module.config.json

Development Workflow

1. npx expo start --dev-client
2. Open dev client app on device/simulator
3. Dev client connects to your local dev server
4. Fast Refresh works for JS/TS changes
5. Native code changes require rebuild

Dev Menu

Shake device or press Cmd+D (iOS simulator) / Cmd+M (Android emulator):

  • Reload JS bundle
  • Toggle Fast Refresh
  • Open debugger
  • Performance monitor
  • Element inspector

Config Plugins

Config plugins modify native project configuration at build time without ejecting:

// plugins/withCustomEntitlement.ts
import { ConfigPlugin, withEntitlementsPlist } from 'expo/config-plugins';

const withCustomEntitlement: ConfigPlugin = (config) => {
  return withEntitlementsPlist(config, (mod) => {
    mod.modResults['com.apple.developer.healthkit'] = true;
    mod.modResults['com.apple.developer.healthkit.access'] = ['health-records'];
    return mod;
  });
};

export default withCustomEntitlement;
// app.json
{
  "expo": {
    "plugins": ["./plugins/withCustomEntitlement"]
  }
}

Common Mistakes

Mistake Fix
Running npx expo start without --dev-client Must use --dev-client flag to connect to custom builds
Forgetting to rebuild after adding native module Any native dependency change requires eas build
Using Expo Go config with dev client Remove expo-go specific workarounds
Not registering iOS test devices Run eas device:create before building for physical devices
Mixing development and production profiles Keep eas.json profiles separate and clear
Building for simulator when targeting device Set "simulator": false in the iOS build profile for devices

Quick Reference

Task Command
Install dev client npx expo install expo-dev-client
Configure EAS eas build:configure
Build for iOS simulator eas build --platform ios --profile development
Build locally eas build --platform ios --profile development --local
Start dev server npx expo start --dev-client
Register device eas device:create
Install build eas build:run --platform ios
Submit to TestFlight eas submit --platform ios
Create native module npx create-expo-module my-module --local
Install via CLI
npx skills add https://github.com/bidah/react-native-hifi --skill expo-dev-client
Repository Details
star Stars 27
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator