Edit this page
Learn more about different tools, workflows and extensions available when working with development builds.
Development builds allow you to iterate quickly. However, you can extend the capabilities of your development build to provide a better developer experience when working in teams or customize the build to suit your needs.
Sometimes, restrictive network conditions make it difficult to connect to the development server. The npx expo start
command exposes your development server on a publicly available URL that is accessible through firewalls from around the globe. This option is helpful if you are not able to connect to your development server with the default LAN option or if you want to get feedback on your implementation while you are developing.
To get a tunneled URL, pass the --tunnel
flag to npx expo start
from the command line.
EAS CLI's eas update
command bundles the current state of your JavaScript and asset files into an optimized "update". This update is stored on a hosting service by Expo. A development build of your app can load published updates without needing to check out a particular commit or leave a development machine running.
When a development build launches, it will expose UI to load a development server, or to "Enter URL manually". You can provide a URL manually that will launch a specific branch. The URL follows this pattern:
https://u.expo.dev/[your-project-id]?channel-name=[channel-name]
# Example
https://u.expo.dev/F767ADF57-B487-4D8F-9522-85549C39F43F?channel-name=main
To get your project's ID, use the URL in the app config's expo.updates.url
field. To see a list of channels, run eas channel:list
.
You can load your app on a device that has a compatible build of your custom client by opening a URL of the form {scheme}://expo-development-client/?url={manifestUrl}
. You'll need to pass the following parameters:
parameter | value |
---|---|
scheme | URL scheme of your client (defaults to exp+{slug} where slug is the value set in the app config) |
manifestUrl | URL-encoded URL of an update manifest to load. The URL will be https://u.expo.dev/[your-project-id]?channel-name=[channel-name] |
Example:
exp+app-slug://expo-development-client/?url=https%3A%2F%2Fu.expo.dev%2F767ADF57-B487-4D8F-9522-85549C39F43F%2F%3Fchannel-name%3Dmain
In the example above, the scheme
is exp+app-slug
, and the manifestUrl
is a project with an ID of F767ADF57-B487-4D8F-9522-85549C39F43F
and a channel of main
.
When testing deep links in your development build, such as when navigating to a specific screen in an Expo Router app or testing redirecting back to your app during an Oauth login flow, construct the URL exactly as you would if you were deep-linking into a standalone build of your app (for example, myscheme://path/to/screen
).
Your project must be already open in the development build for an app-specific deep link to work. Cold-launching a development build with an app-specific deep link is not currently supported. Avoid using expo-development-client
in your app-specific deep links in the path, as it is a reserved path used for launching an updated URL.
You can use our endpoint to generate a QR code that can be easily loaded by a development build.
Requests send to https://qr.expo.dev/development-client
when supplied the query parameters such as appScheme
and url
will receive a response with an SVG image containing a QR code that can be easily scanned to load a version of your project in your development build.
parameter | value |
---|---|
appScheme | URL-encoded deeplinking scheme of your development build (defaults to exp+{slug} where slug is the value set in the app config) |
url | URL-encoded URL of an update manifest to load. The URL will be https://u.expo.dev/[your-project-id]?channel-name=[channel-name] |
Example:
https://qr.expo.dev/development-client?appScheme=exp%2Bapps-slug&url=https%3A%2F%2Fu.expo.dev%2FF767ADF57-B487-4D8F-9522-85549C39F43F0%3Fchannel-name%3Dmain
In the example above, the scheme
is exp+app-slug
, and the url
is a project with an ID of F767ADF57-B487-4D8F-9522-85549C39F43F
and a channel of main
.
These are a few examples of workflows to help your team get the most out of your development build. If you come up with others that would be useful for other teams, please submit a PR to share your knowledge!
You can set up your CI process to publish an EAS Update whenever a pull request is updated and add a QR code that is used to view the change in a compatible development build.
See instructions for publishing app previews on pull requests to implement this workflow in your project using GitHub Actions or serve as a template in your CI of choice.
Extensions allow you to extend your development client with additional capabilities.
The dev menu can be extended to include extra buttons by using the registerDevMenuItems
API:
import { registerDevMenuItems } from 'expo-dev-menu';
const devMenuItems = [
{
name: 'My Custom Button',
callback: () => console.log('Hello world!'),
},
];
registerDevMenuItems(devMenuItems);
This will create a new section in the dev menu that includes the buttons you have registered:
Subsequent calls of
registerDevMenuItems
will override all previous entries.
The EAS Update extension provides the ability to view and load published updates in your development client.
It's available for all development clients v0.9.0
and above. To install it, you'll need the most recent publish of expo-updates
:
-
npx expo install expo-dev-client expo-updates
If you have not yet configured EAS Updates in your project, you can find additional instructions on how to do so here.
You can now view and load EAS Updates in your development build via the Extensions
panel.
When you create a development build of your project, you'll get a stable environment to load any changes to your app that are defined in JavaScript or other asset-related changes. Other changes to your app, whether defined directly in android and ios directories or by packages or SDKs you choose to install, will require you to create a new build of your development build.
To enforce an API contract between the JavaScript and native layers of your app, you should set the runtimeVersion
value in the app config. Each build you make will have this value embedded and will only load bundles with the same runtimeVersion
, in both development and production.