Skip to content

Fix: Expo Not Working — Build Failing, Native Module Not Found, or EAS Build Error

FixDevs ·

Quick Answer

How to fix Expo issues — Expo Go vs development builds, native module installation with expo-modules-core, EAS Build configuration, bare workflow setup, and common SDK upgrade problems.

The Problem

A native module throws an error when running in Expo Go:

Error: Invariant Violation: `new NativeEventEmitter()` requires a non-null argument.

Or the app crashes with a “module not found” error after installing a package:

Unable to resolve module 'expo-camera' from 'src/App.tsx':
None of these files exist: expo-camera/build/...

Or an EAS Build fails with a cryptic Gradle or Xcode error:

> Task :app:processDebugResources FAILED
AAPT: error: resource attr/colorPrimary (aka com.myapp:attr/colorPrimary) not found.

Or after upgrading the Expo SDK, features stop working:

Error: Cannot find native module 'ExpoCamera'

Why This Happens

Expo has two distinct workflows with different constraints:

  • Expo Go only supports Expo SDK modules — Expo Go is a pre-built app that includes a fixed set of native modules. Any package with custom native code that isn’t part of the Expo SDK won’t work in Expo Go. You need a development build for those packages.
  • Native modules require a build step — JavaScript-only packages work immediately after npm install. Native modules (anything with android/ and ios/ directories) require running npx expo prebuild or rebuilding the native project. Without this, the module is installed but its native code isn’t linked.
  • EAS Build differences from local builds — EAS builds run in a clean CI environment. Environment variables, credentials, and native project modifications (patches, custom gradle scripts) must be explicitly configured.
  • SDK upgrades change native dependencies — major Expo SDK upgrades update the underlying React Native version and native module APIs. Running npx expo install (not npm install) ensures version-compatible packages.

Fix 1: Use the Right Workflow for Your Needs

Expo Go — zero setup, great for prototyping, limited to Expo SDK modules:

# Create a new Expo project
npx create-expo-app MyApp

# Start dev server
npx expo start
# Scan QR code with Expo Go app

Development Build — custom native modules, most like production:

# Install expo-dev-client
npx expo install expo-dev-client

# Build a development client for your device
npx eas build --profile development --platform ios
# OR locally (requires Xcode/Android Studio):
npx expo run:ios
npx expo run:android

# Start the dev server (points to your dev build)
npx expo start --dev-client

When to use each:

FeatureExpo GoDevelopment Build
Custom native modules
All Expo SDK packages
No build required
Production-like behavior
Over-the-air updates (EAS Update)

Fix 2: Install Native Modules Correctly

Always use npx expo install instead of npm install for Expo packages — it picks the version compatible with your SDK:

# CORRECT — Expo-compatible version
npx expo install expo-camera expo-location expo-notifications

# WRONG — may install incompatible version
npm install expo-camera  # Might install wrong version for your SDK

# Check if installed packages are compatible with current SDK
npx expo install --check

# Fix incompatible packages
npx expo install --fix

After installing a native module, rebuild the native project:

# Option 1: Prebuild (managed workflow → bare workflow)
npx expo prebuild
# Creates android/ and ios/ directories with native code

# Option 2: Run directly (rebuilds automatically)
npx expo run:ios    # Builds and runs on iOS simulator
npx expo run:android  # Builds and runs on Android emulator/device

# Option 3: EAS Build
npx eas build --profile development --platform all

Verify a package works with Expo:

# Check Expo compatibility
npx expo install --check some-package

# Look for the Expo config plugin
# expo-modules-core compatible packages have an app.json plugin or
# an expo-module.config.json in their package

Fix 3: Configure app.json and Expo Plugins

Native modules often require config plugins to modify the native project:

// app.json
{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "version": "1.0.0",
    "sdkVersion": "52.0.0",
    "platforms": ["ios", "android"],

    "plugins": [
      // Simple plugin — string
      "expo-camera",

      // Plugin with options
      ["expo-camera", {
        "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera."
      }],

      // expo-notifications requires extensive config
      ["expo-notifications", {
        "icon": "./assets/notification-icon.png",
        "color": "#ffffff",
        "sounds": ["./assets/notification.wav"]
      }],

      // Custom plugin
      "./plugins/withCustomGradleConfig"
    ],

    "ios": {
      "bundleIdentifier": "com.yourcompany.myapp",
      "buildNumber": "1",
      "infoPlist": {
        "NSLocationWhenInUseUsageDescription": "Used to show nearby restaurants."
      }
    },

    "android": {
      "package": "com.yourcompany.myapp",
      "versionCode": 1,
      "permissions": [
        "ACCESS_FINE_LOCATION",
        "CAMERA"
      ]
    },

    "extra": {
      "eas": {
        "projectId": "your-eas-project-id"
      }
    }
  }
}

After changing app.json plugins, re-run prebuild:

npx expo prebuild --clean  # --clean removes and regenerates native dirs
# Then rebuild:
npx expo run:ios

Fix 4: Set Up EAS Build

# Install EAS CLI
npm install -g eas-cli

# Login to Expo account
eas login

# Initialize EAS in your project
eas build:configure
# Creates eas.json
// eas.json
{
  "cli": {
    "version": ">= 12.0.0"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "simulator": true
      }
    },
    "preview": {
      "distribution": "internal",
      "android": {
        "buildType": "apk"  // APK for internal distribution
      }
    },
    "production": {
      "ios": {
        "credentialsSource": "remote"
      },
      "android": {
        "buildType": "app-bundle"  // AAB for Play Store
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "[email protected]",
        "ascAppId": "1234567890"
      },
      "android": {
        "serviceAccountKeyPath": "./google-service-account.json"
      }
    }
  }
}
# Build for development
eas build --profile development --platform ios

# Build for all platforms
eas build --profile production --platform all

# Submit to app stores
eas submit --platform ios
eas submit --platform android

Fix common EAS Build errors:

# "Gradle build failed" — often a dependency conflict
# In eas.json, add:
{
  "build": {
    "production": {
      "android": {
        "gradleCommand": ":app:bundleRelease",
        "buildType": "app-bundle"
      }
    }
  }
}

# Environment variables in EAS Build
eas secret:create --scope project --name API_URL --value https://api.example.com

# Or in eas.json:
{
  "build": {
    "production": {
      "env": {
        "APP_ENV": "production",
        "API_URL": "https://api.example.com"
      }
    }
  }
}

Fix 5: Upgrade Expo SDK

Expo SDK upgrades are non-trivial but the CLI guides you:

# Check current SDK version
npx expo --version

# Upgrade to latest SDK
npx expo install expo@latest

# Install compatible versions of all Expo packages
npx expo install --fix

# For major version upgrades, use the upgrade command
npx expo upgrade
# Follow the prompts — it updates app.json sdkVersion and dependencies

# After upgrading, check for breaking changes
# https://expo.dev/changelog

Common post-upgrade fixes:

# Clear caches after upgrade
npx expo start --clear
# iOS:
npx expo run:ios --no-install  # Skip pod install if already done
cd ios && pod install  # Then manually run pod install
# Android:
cd android && ./gradlew clean

# If prebuild generates conflicts with manual native changes:
npx expo prebuild --clean  # WARNING: overwrites ios/ and android/

Fix 6: Over-the-Air Updates with EAS Update

Push JavaScript changes without a new app store submission:

# Install EAS Update
npx expo install expo-updates

# Configure
eas update:configure

# Push an update to the preview channel
eas update --branch preview --message "Fix login bug"

# Push to production
eas update --branch production --message "v1.2.0 release"
// app.json — configure update channels
{
  "expo": {
    "updates": {
      "url": "https://u.expo.dev/your-project-id",
      "fallbackToCacheTimeout": 0,
      "checkAutomatically": "ON_LOAD"
    },
    "runtimeVersion": {
      "policy": "appVersion"  // New native build required when app version changes
    }
  }
}
// Manually check for updates in app
import * as Updates from 'expo-updates';

async function checkForUpdate() {
  try {
    const update = await Updates.checkForUpdateAsync();
    if (update.isAvailable) {
      await Updates.fetchUpdateAsync();
      await Updates.reloadAsync();  // Restart with new version
    }
  } catch (error) {
    console.error('Update check failed:', error);
  }
}

Still Not Working?

“Module not found” after npx expo install — you installed the package but didn’t rebuild the native code. JavaScript-only packages work immediately, but packages with native code require npx expo run:ios or npx expo run:android to link the native modules. If using Expo Go, check if the package is supported — look for “Expo Go” compatibility on the package’s Expo documentation page.

App works on simulator but crashes on device — common causes: (1) permissions not declared in app.json — add required permissions to the ios.infoPlist or android.permissions sections, (2) architecture mismatch — physical iOS devices require arm64 builds, simulators use x86_64/arm64, (3) provisioning profile issues — check your Apple Developer account and EAS credentials.

Hermes engine errors — Expo 50+ uses Hermes by default. Hermes doesn’t support all JavaScript features (some Proxy and Reflect behaviors differ). If a package fails only on Hermes, check if the package has a known Hermes incompatibility. As a last resort, disable Hermes in app.json:

{
  "expo": {
    "jsEngine": "jsc"  // Switch back to JavaScriptCore — not recommended
  }
}

For related React Native issues, see Fix: React Native Android Build Failed and Fix: React Native Metro Bundler Failed.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles