HomeGuidesReferenceLearn
ArchiveExpo SnackDiscord and ForumsNewsletter

Install Expo modules in an existing React Native project

Learn how to prepare your existing React Native project to install and use any Expo module.


To use Expo modules in your app, you will need to install and configure the expo package.

The expo package has a small footprint; it includes only a minimal set of packages that are needed in nearly every app and the module and autolinking infrastructure that other Expo SDK packages are built with. Once the expo package is installed and configured in your project, you can use npx expo install to add any other Expo module from the SDK.

Depending on how you initialized the project, there are two ways you can install the Expo modules: automatically or manually.

Automatic installation

To install and use Expo modules, the easiest way to get up and running is with the install-expo-modules command.

Terminal
# Install and configure the expo package automatically
npx install-expo-modules@latest
  • When the command succeeds, you will be able to add any Expo module in your app! Proceed to Usage for more information.

  • If the command fails, please follow the manual installation instructions. Updating code programmatically can be tricky, and if your project deviates significantly from a default React Native project, then you need to perform manual installation and adapt the instructions here to your codebase.

Manual installation

The following instructions apply to installing the latest version of Expo modules in React Native 0.73.

Terminal
npm install expo

Once installation is complete, apply the changes from the following diffs to configure Expo modules in your project. This is expected to take about five minutes, and you may need to adapt it slightly depending on how customized your project is.

Configuration for Android

Configuration for iOS

Optionally, you can also add additional delegate methods to your AppDelegate.mm. Some libraries may require them, so unless you have a good reason to leave them out, it is recommended to add them. See delegate methods in AppDelegate.mm.

Save all of your changes. In Xcode, update the iOS Deployment Target under Target → Build Settings → Deployment to iOS 13.4. The last step is to install the project's CocoaPods again to pull in Expo modules that are detected by use_expo_modules! directive that we added to the Podfile:

Terminal
# Install pods
npx pod-install

# Alternatively, the run command will install them for you
npx expo run:ios

Optional: use Expo CLI for bundling

We recommend using Expo CLI to bundle your app JavaScript code and assets. This adds support for using the "main" field in package.json supports Expo Router. Learn more about Expo CLI.

Extend expo/metro-config in your metro.config.js
Configure Android project to bundle with Expo CLI
Configure iOS project to bundle with Expo CLI

Replace the shell script in the "Bundle React Native code and images" phase under the "Build Phases" tab for your target in Xcode with the following:

if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then
  source "$PODS_ROOT/../.xcode.env"
fi
if [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then
  source "$PODS_ROOT/../.xcode.env.local"
fi

# The project root by default is one level up from the ios directory
export PROJECT_ROOT="$PROJECT_DIR"/..

if [[ "$CONFIGURATION" = *Debug* ]]; then
  export SKIP_BUNDLING=1
fi
if [[ -z "$ENTRY_FILE" ]]; then
  # Set the entry JS file using the bundler's entry resolution.
  export ENTRY_FILE="$("$NODE_BINARY" -e "require('expo/scripts/resolveAppEntry')" "$PROJECT_ROOT" ios relative | tail -n 1)"
fi

if [[ -z "$CLI_PATH" ]]; then
  # Use Expo CLI
  export CLI_PATH="$("$NODE_BINARY" --print "require.resolve('@expo/cli')")"
fi
if [[ -z "$BUNDLE_COMMAND" ]]; then
  # Default Expo CLI command for bundling
  export BUNDLE_COMMAND="export:embed"
fi

`"$NODE_BINARY" --print "require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'"`

And add support the "main" field in package.json by making the following change to AppDelegate.mm:

 - (NSURL *)getBundleURL
 {
 #if DEBUG
-  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
+  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
 #else
   return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
 #endif

Usage

Verifying installation

You can verify that the installation was successful by logging a value from expo-constants.

  • Run npx expo install expo-constants
  • Then, run npx expo run and modify your app JavaScript code to add the following:
import Constants from 'expo-constants';
console.log(Constants.systemFonts);

Using Expo SDK packages

Once the expo package is installed and configured in your project, you can use npx expo install to add any other Expo module from the SDK. See Using Libraries for more information.

Expo modules included in the expo package

The following Expo modules are brought in as dependencies of the expo package:

  • expo-application - Generates the installation id in remote logging in development. This module is optional and can be safely removed if you do not use expo-dev-client.
  • expo-asset - A JavaScript-only package that builds around expo-file-system and provides a common foundation for assets across all Expo modules.
  • expo-constants - Provides access to the manifest.
  • expo-file-system - Interact with the device file system. Used by expo-asset and many other Expo modules. Commonly used directly by developers in application code.
  • expo-font - Load fonts at runtime. This module is optional and can be safely removed, however; it is recommended if you use expo-dev-client for development and it is required by @expo/vector-icons.
  • expo-keep-awake - Prevents your device from going to sleep while developing your app. This module is optional and can be safely removed.

To exclude any of these modules, refer to the following guide on excluding modules from autolinking.

Excluding specific modules from autolinking

If you need to exclude Expo modules that you are not using but they got installed by other dependencies, you can use the expo.autolinking field in package.json:

package.json
{
  "name": "...",
  "dependencies": {},
  "expo": {
    "autolinking": {
      "exclude": ["expo-keep-awake"]
    }
  }
}

You can also exclude a specific platform by using exclude under the platform key:

package.json
{
  "name": "...",
  "dependencies": {},
  "expo": {
    "autolinking": {
      "exclude": ["expo-font"],
      "ios": {
        "exclude": ["expo-keep-awake"]
      }
    }
  }
}