This documentation refers to the Local Expo CLI (SDK 46 and greater). For information on legacy Expo CLI, see
Global Expo CLI.
expo package provides a small and powerful CLI tool
npx expo which is designed to keep you moving fast during app development.
- Start a server for developing your app:
npx expo start.
- Generate the native iOS and Android directories for your project:
npx expo prebuild.
- Build and run the native apps locally:
npx expo run:iosand
npx expo run:android.
- Install and update packages that work with the version of
react-nativein your project:
npx expo install package-name.
npx expocan be used with
To view a list of available commands in Expo CLI, run the following in your project:
npx expo -h
You can also run
yarn expo -hif you prefer to use yarn as the package manager.
The output should look something like below:
Usage $ npx expo
Commands start, export, export:web run:ios, run:android, prebuild install, customize, config login, logout, whoami, registerOptions --version, -v Version number --help, -h Usage info
You can run any command with the
-h flag to learn more about it:
npx expo login -h
Start a development server to work on your project by running:
npx expo start
You can also run
npx expoas an alias to
npx expo start.
This command starts a server on
http://localhost:19000 which a client can use to interact with the bundler. The default bundler is Metro.
The UI that shows up in the process is referred to as the
Terminal UI. It contains a QR code (for the dev server URL) and a list of keyboard shortcuts you can press:
|A||Open the project in Expo Go on Android.|
|Shift + A||Select an Android device or emulator to open.|
|I||Open the project in Expo Go on iOS.|
|Shift + I||Select an iOS Simulator to open.|
|W||Open the project in a web browser. This may require webpack to be installed in your project.|
|R||Reload the app on any connected device.|
|M||Open the dev menu on any connected native device (web not supported).|
|Shift + M||Choose more commands to trigger on connected devices.|
This includes toggling the performance monitor, opening the element inspector, reloading the device, and opening the dev menu.
|O||Open project code in your editor. This can be configured with the |
|E||Show development server URL as a QR code in the terminal.|
|?||Show all Terminal UI commands.|
By default, the project is served over a LAN connection. You can change this behavior to localhost-only by using the flag
npx expo start --localhost.
Other available options are:
--port: Port to start the dev server on (does not apply to webpack or tunnel URLs). Default: 19000.
--https: Start the dev server using a secure origin. This is currently only supported on web.
You can force the URL to be any value with the
EXPO_PACKAGER_PROXY_URL environment variable. For example:
npx expo start
Will open apps to:
:80 is a temporary workaround for Android websockets).
Restrictive network conditions (common for public Wi-Fi), firewalls (common for Windows users), or Emulator misconfiguration can make it difficult to connect a remote device to your dev server over lan/localhost.
Sometimes it's easier to connect to a dev server over a proxy URL that's accessible from any device with internet access, this is referred to as tunneling.
npx expo start provides built-in support for tunneling via ngrok.
To enable tunneling, first install
npm i -g @expo/ngrok
Then run the following to start your dev server from a tunnel URL:
npx expo start --tunnel
This will serve your app from a public URL like:
- Tunneling is slower than local connections because requests must be forwarded to a public URL.
- Tunnel URLs are public and can be accessed by any device with a network connection. Expo CLI mitigates the risk of exposure by adding entropy to the beginning of the URL. Entropy can be reset by clearing the
.expodirectory in your project.
- Tunnels require a network connection on both devices, meaning this feature cannot be used with the
You can develop without a network connection by using the
npx expo start --offline
Offline will prevent the CLI from making network requests. If you don't use the flag and your computer has no internet connection, then offline support will automatically be enabled, it will just take a bit longer to verify the reachability.
Expo CLI makes network requests to sign manifests with your user credentials to ensure sensitive information is sandboxed in reusable runtimes like Expo Go.
You can compile your app locally with the
# Build for iOS
npx expo run:ios
# Build for Android
npx expo run:android
- Build directly on connected devices with no global side effects using the
--deviceflag. Supports locked devices, letting you retry instantly instead of needing to rebuild.
- Automatically codesign iOS apps for development from the CLI without having to open Xcode.
- Smart log parsing show you warnings and errors from your project source code, unlike Xcode which surfaces hundreds of benign warnings from your node modules.
- Fatal errors causing your app to crash will be surfaced to the terminal preventing the need to reproduce in Xcode.
expo run:ios can only be run on a Mac, and Xcode must be installed. You can build the app in the cloud from any computer using
eas build -p ios. Similarly,
expo run:android requires Android Studio and Java to be installed and configured on your computer.
Building locally is useful for developing native modules and debugging complex native issues. Building remotely with
eas build is a much more resilient option due to the preconfigured cloud environment.
If your project does not have the corresponding native directories, the
npx expo prebuild command will run once to generate the respective directory before building.
For example, if your project does not have a root
ios/ directory, then
npx expo run:ios will first run
npx expo prebuild -p ios before compiling your app. Learn more about this process in the Expo Prebuild doc.
--no-build-cache: Clear the native cache before building. On iOS this is the derived data folder. Cache clearing is useful for profiling your build times.
--no-install: Skip installing dependencies. On iOS this will also skip running
npx pod-installif the
dependenciesfield in the project's
--no-bundler: Skip starting the dev server. Enabled automatically if the dev server is already serving the app from a different process.
-d, --device [device]: Device name or ID to build the app on. You can pass
--devicewithout arguments to select a device from a list of available options. This supports connected devices as well as virtual devices.
-p, --port <port>: Port to start the development server. Default: 8081. This is only relevant for development builds. Production builds will export the project and embed the files in the native binary before installing on a device.
An iOS app can have multiple schemes for representing different sub-apps like App Clips, watchOS apps, Safari Extensions, and so on. By default,
expo run:ios will choose the scheme for your iOS app. You can pick a custom scheme with the
--scheme <my-scheme> argument. If you pass in the
--scheme argument alone, then Expo CLI will prompt you to choose a scheme from the list of available options in your Xcode project.
The scheme you select will filter out which
--device options show up in the selection prompt, for example, selecting an Apple TV scheme will only show available Apple TV devices.
You can compile an iOS app for production by running:
npx expo run:ios --configuration Release
This build is not automatically code signed for submission to the Apple App Store.
npx expo run:ios should mostly be used to test bugs that only show up in production builds. Native code signing requires several network requests and is prone to many different types of errors from the Apple servers. To generate a production build that is code signed for the App Store, we recommend using EAS Build.
When you compile your app onto a Simulator, the Simulator's native error logs will be piped to the Expo CLI process in the terminal. This is useful for quickly seeing bugs that may cause a fatal error. For example, missing permission messages. Error piping is not available for physical iOS devices.
You can debug using
lldb and all of the native Apple debugging tools by opening the project in Xcode and rebuilding from Xcode:
Building from Xcode is useful because you can set native breakpoints and profile any part of the application. Be sure to track changes in source control (git) in case you need to regenerate the native app with
npx expo prebuild -p ios --clean.
iOS development signing
If you want to see how your app will run on your device, all you have to do is connect it, run
npx expo run:ios —-device, select your connected device.
Expo CLI will automatically sign the device for development, install the app, and launch into it.
If you don't have any developer profiles setup on your computer then you'll need to set them up manually outside of Expo CLI by following this guide: Setup Xcode signing.
Android apps can have multiple different variants which are defined in the project's
build.gradle file. Variants can be selected with the
npx expo run:android --variant debug
You can compile the Android app for production by running:
npx expo run:android --variant release
This build is not automatically code signed for submission to the Google Play Store. This command should be used to test bugs that may only show up in production builds. To generate a production build that is code signed for the Play Store, we recommend using EAS Build.
You can debug the native Android project using native debugging tools by opening the
android/ folder in Android Studio:
open -a /Applications/Android Studio.app android
npx expo export
This is done automatically when using
eas update or when compiling the native runtime. The
export command works similar to most web frameworks:
- A bundler transpiles and bundles your application code for production environments, stripping all code guarded by the
- All static files are copied into a static
dist/folder which can be served from a static host.
- Contents of the
public/folder are copied into the
The following options are provided:
--platform <platform>: Choose the platform to compile for: 'ios', 'android', 'all'. Default: all. 'web' is also available if configured in the Expo config. For more information, see Customizing Metro.
--dev: Bundle for development environments without minifying code or stripping the
--output-dir <dir>: The directory to export the static files to. Default: dist
--max-workers <number>: Maximum number of tasks to allow the bundler to spawn. Setting this to
0will run all transpilation on the same process, meaning you can easily debug Babel transpilation.
-c, --clear: Clear the bundler cache before exporting.
Exporting with webpack
webpack is only supported for the Web platform.
npx expo export:web
--dev: Bundle in 'development' mode without minifying code or stripping the
-c, --clear: Clear the bundler cache before exporting.
This command will be disabled if your project is configured to use
metro for bundling web projects in the
app.json via the
expo.web.bundler: 'metro' field.
npx expo prebuild
Native source code must be generated before a native app can compile. Expo CLI provides a unique and powerful system called prebuild, that generates the native code for your project. To learn more, read the Expo Prebuild docs.
Evaluate the Expo config (app.json, or app.config.js) by running:
npx expo config
--full: Include all project config data.
--json: Output in JSON format, useful for converting an
-t, --type: Type of config to show.
There are three different config types that are generated from the Expo config:
public: The manifest file to use with OTA updates. Think of this like an
<head />element but for native apps.
prebuild: The config that is used for Expo Prebuild including async modifiers. This is the only time the config is not serializable.
introspect: A subset of the
prebuildconfig that only shows in-memory modifications like
AndroidManifest.xmlchanges. Learn more about introspection.
Unlike the web, React Native is not backwards compatible. This means that npm packages often need to be the exact right version for the currently installed copy of
react-native in your project. Expo CLI provides a best-effort tool for doing this using a list of popular packages and the known working version combinations. Simply use the
install command as a drop-in replacement for
npx expo install expo-camera
Running a single instance of this command, you can also install multiple packages:
npx expo install typescript expo-sms
You can directly pass arguments to the underlying package manager by using the
yarn expo install typescript -- -D
# yarn add typescript -D
You can perform validation and correction with the
--check: Check which installed packages need to be updated.
--fix: Automatically update any invalid package versions.
# Check all packages for incorrect versions, prompt to fix locally
npx expo install --check
npx expo install --check prompts you about packages that are installed incorrectly. It also prompts about installing the these packages to their compatible versions locally. It exits with non-zero in Continuous Integration (CI). This means you can use this to do continuous immutable validation. In contrast,
npx expo install --fix will always fix packages if needed, regardless of the environment.
You can validate specific packages by passing them:
# Check only react-native and expo-sms
npx expo install react-native expo-sms --check
npx expo install expo-camera and
npx expo install expo-camera --fix serve the same purpose, the
--fix command is useful for upgrading all packages in your project like:
npx expo install --fix
Install package managers
npx expo install has support for
You can force the package manager using a named argument:
--npm: Use npm to install dependencies. Default when
--yarn: Use Yarn to install dependencies. Default when
--pnpm: Use pnpm to install dependencies. Default when
Expo CLI provides authentication methods to use with the
npx expo start command. Authentication is used to "code sign" manifests for secure OTA usage. Think of this like HTTPS on the web.
- Register an account with
npx expo register.
- Login to your account with
npx expo login.
- Check which account is currently authenticated with
npx expo whoami.
- Logout with
npx expo logout.
These credentials are shared across Expo CLI and EAS CLI.
Sometimes you may want to customize a project file that would otherwise be generated in memory by Expo CLI. When utilizing tools other than Expo CLI, you'll need to have the default config files present, otherwise your app may not work as expected. You can generate files by running:
npx expo customize
From here, you can choose to generate basic project files like:
babel.config.js-- The Babel configuration. This is required to be present if you plan to use tooling other than Expo CLI to bundle your project.
webpack.config.js-- The default webpack config for web development.
metro.config.js-- The default Metro config for universal development. This is required for usage with
HTTP_PROXY(string) HTTP/HTTPS proxy URL to connect for all network requests. Configures https-proxy-agent.
EXPO_NO_WEB_SETUP(boolean) prevents the CLI from forcing web dependencies (
@expo/webpack-config) to be installed before using web functionality. This is useful for cases where you wish to perform non-standard web development.
EXPO_NO_TYPESCRIPT_SETUP(boolean) prevents the CLI from forcing TypeScript to be configured on
npx expo start. For more information, see TypeScript guide.
DEBUG=expo:*(string) enables debug logs for the CLI, you can configure this using the
EXPO_DEBUG(boolean) an alias for
EXPO_PROFILE(boolean) enable profiling stats for the CLI, this does not profile your application.
EXPO_NO_CACHE(boolean) disable all global caching. By default, Expo config JSON schemas, Expo Go binaries for simulators and emulators, and project templates are cached in the global
.expofolder on your machine.
CI(boolean) when enabled, the CLI will disable interactive functionality, skip optional prompts, and fail on non-optional prompts. Example:
CI=1 npx expo install --checkwill fail if any installed packages are outdated.
EXPO_NO_TELEMETRY(boolean) disables anonymous usage collection. Learn more.
EXPO_NO_GIT_STATUS(boolean) skips warning about git status during potentially dangerous actions like
npx expo prebuild --clean.
EXPO_NO_REDIRECT_PAGE(boolean) disables the redirect page for selecting an app, that shows when a user has
expo-dev-clientinstalled, and starts the project with
npx expo startinstead of
npx expo start --dev-client.
EXPO_PUBLIC_FOLDER(string) public folder path to use with Metro for web. Default:
public. Learn more.
EDITOR(string) name of the editor to open when pressing
oin the Terminal UI. This value is used across many command line tools.
EXPO_EDITOR(string) an Expo-specific version of the
EDITORvariable which takes higher priority when defined.
EXPO_IMAGE_UTILS_NO_SHARP(boolean) disable the usage of global Sharp CLI installation in favor of the slower Jimp package for image manipulation. This is used in places like
npx expo prebuildfor generating app icons.
EXPO_TUNNEL_SUBDOMAIN(boolean) Experimental Disable using
exp.directas the hostname for
--tunnelconnections. This enables https:// forwarding which can be used to test universal links on iOS. This may cause unexpected issues with
expo-linkingand Expo Go. Select the exact subdomain to use by passing a
stringvalue that is not one of:
EXPO_METRO_NO_MAIN_FIELD_OVERRIDE(boolean) force Expo CLI to use the
resolver.resolverMainFieldsfrom the project's metro.config.js for all platforms. By default, Expo CLI will use
['browser', 'module', 'main'], which is the default for webpack, for the web and the user-defined main fields for other platforms.
Expo dev tools collect anonymous data about general usage. This helps us know when a feature is not working as expected. Telemetry is completely optional, you can opt out by using the
EXPO_NO_TELEMETRY=1 environment variable.