Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time

Migration off the expo file extension

TL;DR: Starting in Expo SDK 40, the .expo.js extension is deprecated in favor of optional imports.

Files with the .expo.* extension will no longer be used in SDK 41+, the EXPO_TARGET environment variable, and the --target flag on expo publish, and expo export are all deprecated.


In the past, it was impossible to import files that didn't exist using the Metro bundler. Even if you wrapped a require statement in a try/catch, Metro would just fail to bundle instead of throwing. We've upstreamed a fix in SDK 40+ which correctly throws an error:

try {
  // If expo-camera doesn't exist, Metro would just crash instead of throwing :(
} catch (error) {
  // Starting in SDK 40+ the error will be thrown meaning you can optionally check if modules exist!

To work around this, we created the .expo.js extension which would get used in the Expo client and classic standalone builds (expo build). This feature was primarily used by library authors who wanted to support alternative APIs like react-native-camera if expo-camera wasn't installed in the project. In SDK 40+ this can be done using try/catch syntax.


Alternative Modules

If you wanted to use expo-camera in your app when running in Expo Go, but some other package when running outside of Expo Go, you had to use a workflow extension.


You used to have to create a "workflow specific" file extension before optional imports

Camera.expo.js (this file would be used in Expo environments)

export * from "expo-camera";

Camera.js (this file would be used in all other environments)

export * from "another-camera-package";


Now you can use the optional import syntax instead:


let camera;
try {
  camera = require("expo-camera");
} catch {
  camera = require("another-camera-package");
module.exports = camera;

Detecting Expo

If you wanted to detect if you were running in Expo Go, you needed to use workflow extensions, instead, you should use expo-constants.


isExpo.expo.js (this file would be used in Expo environments)

export const isExpo = true;

isExpo.js (this file would be used in all other environments)

export const isExpo = false;


Now you can use a far more reasonable approach:

let isExpo = false;
try {
  const Constants = require("expo-constants");
  // True if the app is running in an `expo build` app or if it's running in Expo Go.
  isExpo =
    Constants.executionEnvironment === "standalone" ||
    Constants.executionEnvironment === "storeClient";
} catch {}


We've decided to deprecate the .expo.* workflow extension as soon as possible because it's a nonstandard bundler feature which adds increased complexity to React projects. Lower complexity means it's easier to make other bundlers and tools work with Expo.