1--- 2title: Internal distribution 3description: Learn how EAS Build provides shareable URLs for your builds with your team for internal distribution. 4--- 5 6import { Collapsible } from '~/ui/components/Collapsible'; 7import { Terminal } from '~/ui/components/Snippet'; 8import { Step } from '~/ui/components/Step'; 9 10Uploading your app to TestFlight and Google Play beta can be time-consuming (for example, waiting for the build to run through static analysis before becoming available to testers) and limiting (for example, TestFlight can only have one active build at a time). Both Android and iOS provide alternative mechanisms to distribute apps directly to testers, so they can download and install them to physical devices directly from a web browser as soon as the builds are completed. 11 12EAS Build can help you with this by providing shareable URLs for your builds with instructions on how to get them running, so you can share a single URL with a teammate that'll include all of the information they need to test the app. 13 14> Installing an app on iOS is a bit trickier than on Android, but it's possible thanks to ad hoc and enterprise provisioning profiles. We'll talk more about this later in this doc. 15 16## Setting up internal distribution 17 18The following steps will guide you through adding internal distribution to a project that is [already set up to build with EAS Build](setup.mdx). It will only take a few minutes in total to: 19 20- Configure the project 21- Add a couple of test iOS devices to a provisioning profile 22- Start builds for Android and iOS 23 24<Step label="1"> 25 26## Configure a build profile 27 28Open **eas.json** in your project. You can use the pre-configured `preview` profile or [create a new one](/build/eas-json/#build-profiles) for Android or iOS. 29 30```json eas.json 31{ 32 "build": { 33 "preview": { 34 "distribution": "internal" 35 } 36 } 37} 38``` 39 40### Android 41 42Note that if you override the `gradleCommand` on Android, you should ensure that it produces an **.apk** rather than an **.aab**, so it is directly installable to an Android device. 43 44### iOS 45 46The configuration above tells EAS Build that you would like to use ad hoc distribution, which is available for all paid Apple Developer accounts. It is not available for free accounts. 47 48<Collapsible summary="Do you have an Apple Developer Enterprise Program membership?"> 49 50The following will only work if you have an Apple account with Apple Developer Enterprise Program membership. While using Enterprise provisioning, you can sign your app using a `universal` or `adhoc` provisioning profile. We recommend `universal` because it does not require you to register your devices with Apple, which is the main benefit of using Enterprise provisioning. 51 52```json 53{ 54 "build": { 55 "preview": { 56 "distribution": "internal", 57 "ios": { 58 /* @info Valid values: universal, adhoc */ 59 "enterpriseProvisioning": "universal" /* @end */ 60 } 61 } 62 } 63} 64``` 65 66</Collapsible> 67 68</Step> 69 70<Step label="2"> 71 72## Configure app signing 73 74<Step label="2.1"> 75 76### Configure app signing credentials for Android 77 78Android does not restrict distribution of applications — the operating system is capable of installing any compatible **.apk** file. As a result, configuring app signing credentials for internal distribution is no different from other types of builds. The main benefit of using internal distribution, in this case, is to have an easily shareable URL to provide to testers for downloading the app. 79 80</Step> 81 82<Step label="2.2"> 83 84### Configure app signing credentials for iOS 85 86Apple restricts distribution of applications on iPhones and iPads, so we will need to build the app with an ad hoc provisioning profile that explicitly lists the devices on which the application can run. 87 88An alternative to ad hoc provisioning is enterprise provisioning, which requires a special Apple Developer membership that costs $299 USD per year. Enterprise provisioning allows you to run the application on any device without any sort of device registration. 89 90</Step> 91 92#### Setting up ad hoc provisioning 93 94Apps signed with an ad hoc provisioning profile can be installed by any iOS device whose unique identifier (UDID) is registered with the provisioning profile. 95 96Setting up ad hoc provisioning consists of two steps. In the first step, you'll register devices that you want to be able to install your app. Run the following command to generate a URL (and QR code, for convenience) that you can open on your devices, and then follow the instructions on the registration page. 97 98<Terminal cmd={['# Register Apple Devices for internal distribution', '$ eas device:create']} /> 99 100You can register new devices at any time, but builds that were created before the device was registered will not run on newly registered devices; only builds that are created after the device is registered will be installable. 101 102The next step is to generate or update the provisioning profile. When you proceed to run a build, you will be guided through this process. 103 104<Collapsible summary="Are you setting up enterprise provisioning?"> 105 106Apple Enterprise Program membership costs $299 USD per year and [not all organizations will be eligible](https://developer.apple.com/programs/enterprise/), so you will likely be using ad hoc provisioning, which works with any normal paid Apple Developer account. 107 108If you have an [Apple Developer Enterprise Program membership](https://developer.apple.com/programs/enterprise/) users can install your app to their device without pre-registering their UDID; they just need to install the profile to their device and they can then access existing builds. You will need to sign in using your Apple Developer Enterprise account during the `eas build` process to set up the correct provisioning. 109 110If you distribute your app both through enterprise provisioning and the App Store, you will need to have a distinct bundle identifier for each context. We recommend either: 111 112- In managed projects, use **app.config.js** to dynamically switch identifiers. 113- In bare projects, create a separate `scheme` for each bundle identifier and specify the scheme name in separate build profiles. 114 115</Collapsible> 116 117<Collapsible summary="Are you using manual local credentials?"> 118 119If so, make sure to point your **credentials.json** to an ad hoc or enterprise provisioning profile that you generate through the Apple Developer Portal (either update an existing **credentials.json** used for another type of distribution or replace it with a new one that points to the appropriate provisioning profile). Beware that EAS CLI does only a limited validation of your local credentials, and you will have to handle device UDID registration manually. Read more about [using local credentials](/app-signing/local-credentials). 120 121</Collapsible> 122 123</Step> 124 125<Step label="3"> 126 127## Run a build with the internal build profile 128 129Now that we have set up our build profile and app signing, running a build for internal distribution is just like any other build. 130 131<Terminal 132 cmd={[ 133 '# Create Android and iOS builds for internal distribution', 134 '$ eas build --profile preview --platform all', 135 ]} 136 cmdCopy="eas build --profile preview --platform all" 137/> 138 139> If you're using ad hoc provisioning but you haven't registered any devices yet, you'll be asked to register them now (or exit the current command and run `eas device:create` again). The build command will wait for the new device to register. Scan the QR code that is presented in the terminal and follow the instructions on that page to register your device. When you're done, return to the terminal and continue. 140 141When the build completes, you will be given a URL that you can share with your team to download and install the app. 142 143</Step> 144 145<Step label="4"> 146 147## Install and run the build 148 149Press the "Install" button on the build page and follow the instructions presented in the modal. 150 151If you're running iOS 16 or above and haven't yet turned on Developer Mode, you will need to [enable it](/guides/ios-developer-mode) before you can run your build. This doesn't apply if you're using enterprise provisioning. 152 153</Step> 154 155<Step label="5"> 156 157## Automation on CI (optional) 158 159It's possible to run internal distribution builds non-interactively in CI using the `--non-interactive` flag; however, if you are using ad hoc provisioning on iOS you will not be able to add new devices to your provisioning profile when using this flag. After registering a device through `eas device:create`, you need to run `eas build` interactively and authenticate with Apple for EAS to add the device to your provisioning profile. [Learn more about triggering builds from CI](/build/building-on-ci). 160 161</Step> 162 163{/* (@dsokal) this is not implemented yet */} 164 165{/* When using iOS ad hoc provisioning managed by Expo, if a teammate navigates to this URL on an iOS device that is not yet registered, they will be able to register their device and initiate a new build to include the updated profile that will run on their device. If the ad hoc provisioning profile is not managed by Expo, the user will be asked to contact the organization admin to add their device UDID and create a new build compatible with their device. */} 166 167## Managing devices 168 169You can see any devices registered via `eas device:create` by running: 170 171<Terminal 172 cmd={['# List devices registered for ad hoc provisioning', '$ eas device:list']} 173 cmdCopy="eas device:list" 174/> 175 176Devices registered with Expo for ad hoc provisioning will appear on your Apple Developer Portal after they are used to generate a provisioning profile for a new internal build with EAS Build or to [resign an existing build](/app-signing/app-credentials/#re-signing-new-credentials) with `eas build:resign`. 177 178### Remove devices 179 180If a device is no longer in use, it can be removed from this list by running: 181 182<Terminal 183 cmd={[ 184 '# Delete devices from your Expo account, optionally disable them on the Apple Developer Portal', 185 '$ eas device:delete', 186 ]} 187 cmdCopy="eas device:delete" 188/> 189This command will also prompt you to disable the device on the Apple Developer Portal. Disabled devices 190still count against [Apple's limit of 100 devices](https://developer.apple.com/support/account/#:~:text=Resetting%20your%20device%20list%20annually) 191for ad hoc distribution per app. 192 193### Rename devices 194 195Devices added via the website URL/QR code will default to displaying their UDID when selecting them for an EAS Build. You can assign friendly names to your devices with the following command: 196 197<Terminal 198 cmd={['# Rename devices on Expo and the Apple Developer Portal', '$ eas device:rename']} 199 cmdCopy="eas device:rename" 200/> 201