skip to content

In an Expo project, what does expo-dev-client add to a debug build, and how does that development build find the Metro dev server?

level: middleimportance: should knowfreq 38%

answer

  1. launcher screen and dev menu
  2. servers on the local network
  3. exp+ plus the slug as scheme
  4. expo-development-client/?url= deep link
  5. --dev-client, --go, press s

basics

~20 s

expo-dev-client adds a launcher screen, an extended dev menu and the ability to load published updates. The build finds Metro through the launcher's list of dev servers on the network, or through a QR code deep link carrying the server URL.

solid answer

~40 s

`expo-dev-client` turns a Debug build into a development build: it adds a **launcher** screen that lists development servers and lets you enter a URL, an extended **dev menu**, and support for opening published updates. Its config plugin also registers a custom URL scheme, by default `exp+` followed by the app's slug (`addGeneratedScheme` defaults to `true`). When `package.json` depends on `expo-dev-client`, `npx expo start` switches to development-build mode, prints *Using development build*, and its QR code encodes `exp+<slug>://expo-development-client/?url=<manifest URL>`, which opens your build and points it at Metro. The launcher also finds a bundler on the local network, or through the same Expo account signed in on both sides. `--dev-client` and `--go` force a target, and pressing `s` switches between them.

code

bash · 4 lines
bash
npx expo install expo-dev-client
npx expo run:android        # native rebuild: the launcher is native code
npx expo start              # prints "Using development build"
npx expo start --go         # force Expo Go instead

go deeper

for a junior

Recall that expo-dev-client adds a launcher and dev menu, and that scanning the QR code from npx expo start opens your build.

for a middle

Explain the connection paths: network discovery, account sign-in, and the exp+slug deep link carrying the manifest URL, plus how the CLI picks its target.

for a senior

Show how you debug a build that cannot find Metro, and how one shared development build serves many developers and branch previews.

for a principal

Decide how development builds and their servers are shared across a team so that switching context never costs a native rebuild.

## What a plain Debug build knows about Metro A React Native Debug build loads its JavaScript from a development server instead of an embedded bundle. By itself it looks for the server at a host and port it was configured with, which works on a simulator but gets awkward across devices, networks and teammates. `expo-dev-client` adds a proper front door. ## What expo-dev-client adds - **The launcher**: the first screen when you open the app from the home screen. It lists development servers it can find, accepts a URL, and can open published updates of the app. - **An extended dev menu**, opened by shaking the device or with a keyboard shortcut, for reloading, debugging and switching what the build is running. - **A generated URL scheme**: the config plugin registers `exp+<slug>` on iOS and Android, derived from the app config's `slug`, lowercased, with characters that are not allowed in a scheme removed. Set `addGeneratedScheme: false` in the plugin options to skip it. - **Integration with `npx expo start`**, so the CLI produces links that open the development build rather than Expo Go. Because the launcher and scheme are native, adding `expo-dev-client` itself requires a native build. ## How the build finds Metro 1. **Local network discovery**: if a bundler is detected on the same network, the launcher shows it and you tap to connect. 2. **Account sign-in**: signed in to the same Expo account in the CLI and the development build, the launcher can list your running servers. 3. **QR code or deep link**: `npx expo start` prints a QR code encoding a URL of the form `exp+<slug>://expo-development-client/?url=<encoded manifest URL>`. Scanning it opens your app through its scheme and hands it the server address. 4. **Keyboard shortcuts**: pressing `a` or `i` in the CLI opens the project on an Android emulator or iOS Simulator. ## How npx expo start picks the target | Situation | What the CLI targets | |---|---| | `expo-dev-client` is a direct dependency, no flags | the development build (*Using development build*) | | no `expo-dev-client`, no flags | Expo Go | | `--dev-client` | the development build, even without the library | | `--go` | Expo Go | | pressing `s` while running | switch between the two | Passing both `--dev-client` and `--go` is an error. The docs note that a development build without `expo-dev-client` is possible: start the server with `--dev-client`, or the QR code opens Expo Go. ## Troubleshooting the connection - **The launcher shows no servers**: device and computer are on different networks, or the network blocks discovery. Scan the QR code, or use a tunnel host for the dev server. - **The QR code opens Expo Go**: the project has no direct `expo-dev-client` dependency and the server was started without `--dev-client`. - **The QR code does nothing**: the installed build predates `expo-dev-client` or the scheme; rebuild it. - **A teammate's server appears**: the launcher lists what it can find; confirm the host before debugging someone else's bundle. ## Why teams want the launcher One shared development build can serve many people: each developer points it at their own Metro, reviewers open a published update from a branch, and nobody reinstalls the app for a JavaScript-only change. The launcher is what makes that switching cheap. ## Sharing one build across a team The launcher changes how a team works with builds: - **One build, many servers**: each developer runs `npx expo start` on their own machine and opens the same installed development build against it. - **Branch previews**: reviewers open a published update of a branch from the launcher instead of installing a new app, as long as the branch has no native changes. - **Fewer reinstalls**: the build is replaced only when native code changes, which is exactly when the launcher cannot help. The rule of thumb that follows: JavaScript moves through Metro or updates, native code moves through a new build, and the launcher is the switch between JavaScript sources.

  • What URL scheme does expo-dev-client register for an app whose slug is habit-loop?
    `exp+habit-loop`. The plugin lowercases the slug, removes characters not allowed in a URI scheme, and adds the `exp+` prefix to avoid leading digits and to distinguish it from user-defined schemes. `addGeneratedScheme: false` turns it off.
  • The QR code from npx expo start keeps opening Expo Go instead of the team's development build; why?
    The CLI targets the development build automatically only when `expo-dev-client` is a direct dependency. Without it, the default is Expo Go. Install `expo-dev-client` and rebuild, or start the server with `--dev-client`.

saying these in an interview costs you the question

  • expo-dev-client can be added with only a Metro reload
  • npx expo start always targets Expo Go unless told otherwise
  • The development build must be rebuilt to switch Metro servers
  • The dev client scheme is the same for every Expo app
  • Development builds cannot exist without expo-dev-client