Blog featured image
Digital Health

How to Generate Cloud Builds in React Native Expo

Arun Badole
Head of Engineering

TL;DR

EAS (Expo Application Services) Build moves React Native compilation to the cloud: run one command, get Android and iOS builds without maintaining local SDKs, signing setup, or exposing keys.

    Prerequisites: Setting Up Your Environment

    Before you trigger any cloud build, a few foundations need to be in place. Skipping these often leads to failed builds or credential prompts mid-flow.

    1. Node.js and Package Manager

    Use Node.js v18 or later (LTS is recommended for stability). EAS CLI works with npm, yarn, or Bun—pick whatever your project already uses. Run `node –version` to confirm. If your team uses a specific Node version, consider a version manager (e.g. nvm) so everyone matches.
    Why it matters: The EAS build worker uses a fixed Node version on the server; your local Node version mainly affects running the CLI and scripts. Mismatched Node versions can cause “works on my machine” issues when build scripts or native tooling run differently locally vs in the cloud.

    2. Expo SDK and EAS CLI

    Your project must be an Expo app (managed workflow or with `expo prebuild`). Install or run EAS CLI via your package manager so the version matches what your project expects:
    “`bash
    npx eas-cli –version

    or: bunx eas –version

    “`
    Check the `cli.version` field in your `eas.json` (e.g. `”>= 16.6.1″`). If the installed CLI is older, update it or adjust the constraint so EAS Build accepts your config.
    Tip: Pin the CLI version in `eas.json` so that everyone (and CI) uses the same EAS CLI version. That reduces surprises when new CLI releases change behavior or add required fields.

    3. Expo Account and Login

    Sign up at expo.dev and log in from the CLI. EAS ties every build to your account and project:
    “`bash
    npx eas login
    “`
    Without this, the first `eas build` will prompt you to authenticate. For CI/CD, use token-based auth as described in Expo’s docs—never commit or log credentials.
    Linking a project: The first time you run `eas build`, you’ll be asked to create or link an EAS project. Linking associates your repo with a project on expo.dev so builds, credentials, and OTA updates are scoped to that project. All team members should use the same linked project for shared credentials and build history.

    4. Project Configuration: app.config and eas.json

    Two files drive how EAS Build behaves.
    `app.config.js` or `app.config.ts` holds your Expo app config: `name`, `slug`, `version`, and platform blocks for `ios` and `android`. For EAS you need:

  • `extra.eas.projectId` — Set when you first run `eas build` or link the project in the dashboard. It identifies your project for builds and OTA updates.
  • `updates.url` — If you use OTA updates, point this to `https://u.expo.dev/` so the app knows where to fetch updates.
  • Sensitive values — Never hard code API URLs, OAuth client IDs, or tokens. Use environment variables (e.g. `process.env.EXPO_PUBLIC_API_URL`) and supply real values via EAS Secrets or a local `.env` that is not committed.
  • `eas.json` defines build profiles. Each profile is a named set of options:

  • `distribution` — `”internal”` for ad-hoc/internal installs (Android: APK/AAB via link; iOS: ad-hoc or enterprise). Omit or use `”store”` for Play Store / App Store.
  • `environment` — EAS “environments” (e.g. `development`, `preview`, `production`) determine which set of EAS Secrets is injected. Create environments in the Expo dashboard and assign secrets to them.
  • `channel` — Used by Expo Updates (OTA). The built app checks this channel for over-the-air updates; point each profile to the right channel so preview builds don’t receive production updates.
  • `autoIncrement` — When `true`, EAS bumps the Android version code and/or iOS build number automatically so each build is uniquely versioned without editing config.
  • Platform overrides — Under `ios` or `android` you can set options like `ios.simulator: true` (simulator-only iOS build) or `android.buildType: “apk”` (default is AAB for store).
  • Example structure without any secrets:
    “`json
    {
    “cli”: { “version”: “>= 16.6.1” },
    “build”: {
    “development”: {
    “developmentClient”: true,
    “distribution”: “internal”,
    “environment”: “development”,
    “channel”: “development”
    },
    “preview”: {
    “distribution”: “internal”,
    “environment”: “preview”,
    “autoIncrement”: true,
    “channel”: “preview”
    },
    “production”: {
    “environment”: “production”,
    “autoIncrement”: true,
    “channel”: “production”
    }
    }
    }
    “`

    5. Environment Variables and EAS Secrets

    For local development, use a `.env` file and keep it in `.gitignore`. Load variables in `app.config` and in your app so that `EXPO_PUBLIC_*` vars are available at build time.
    For EAS cloud builds, use EAS Secrets. They are injected during the build according to the profile’s `environment`. Create them via CLI or the Expo dashboard:
    “`bash
    npx eas secret:create –scope project –name EXPO_PUBLIC_API_URL –value “https://api.example.com/v1/graphql”
    npx eas secret:list
    “`
    In `app.config`, read via `process.env.EXPO_PUBLIC_*`. Never commit real keys or tokens—only placeholders in docs and real values in EAS Secrets or local `.env`.
    Scope and naming: Secrets can be scoped to the project (`–scope project`) or to an environment. Names must match what your app and `app.config` expect (e.g. `EXPO_PUBLIC_API_URL`). Variables prefixed with `EXPO_PUBLIC_` are exposed to the client bundle; use them only for non-sensitive config (e.g. API base URL). Truly secret values (e.g. API secrets) should not use `EXPO_PUBLIC_` and should be used only in server-side or build-time logic if needed.

    6. Git and Repo State

    EAS Build uses your git repository (or a linked GitHub/GitLab integration). You can optionally include uncommitted changes when starting a build, but for reproducible builds and clear history, commit and push first. That way each build maps to a known commit.
    What gets built: By default EAS builds from the current git state (including uncommitted files if you choose). If you use GitHub/GitLab integration, you can trigger builds from a branch or commit. The build logs and the Expo dashboard show the commit SHA so you can always trace a build back to source.

    What Happens When You Run a Build?

    When you run `eas build`, the CLI uploads your project (or a tarball of it) to EAS. A build worker then:

  • Checks out your code (or uses the uploaded snapshot).
  • Installs dependencies (`npm install` / `yarn` / `bun install`).
  • Injects EAS Secrets for the profile’s `environment`.
  • Runs prebuild if needed (generates native `ios/` and `android/` from your Expo config).
  • Builds the native app (e.g. `xcodebuild` for iOS, Gradle for Android) and signs it with the credentials stored in EAS.
  • Uploads the artifact (IPA, APK, or AAB) and provides a link.
  • Build time varies (often 10–25 minutes depending on platform and cache). You can watch logs in the terminal or on the build page. Caching is enabled by default so dependency install and native build steps are faster on subsequent runs.

Need Help Scaling Your React Native Builds? Talk To Our Mobile Experts.

    Process: Android Cloud Builds

    1. Android Config in app.config

    In your Expo config, the `android` section must define at least:

  • `package` — Your application ID (e.g. `com.yourcompany.yourapp`). It must be unique and consistent for store submissions.
  • `adaptiveIcon` (or `icon`) — So the launcher shows a proper icon. Adaptive icons (foreground + background) improve appearance across launchers.
  • You can also set `versionCode` in the config, or leave it to EAS and use `autoIncrement` in the build profile. Do not put keystores or signing keys in the repo; EAS will create or use stored credentials when you build.
    Output format: For store builds, EAS produces an AAB (Android App Bundle) by default, which is required for Play Store. For internal testing you may get an APK or AAB depending on profile; you can force APK with `”android”: { “buildType”: “apk” }` in the profile if needed for older tooling.

    2. Build Profiles for Android

    Use different profiles for different goals. Preview (or similar) with `distribution: “internal”` is for internal testing; production is for Play Store. Set `environment` so the right EAS Secrets are applied. Optionally use `autoIncrement` so each build gets a new version code without editing config.

    3. First-Time Credentials

    When you run your first Android build, EAS will ask about credentials if none exist. Prefer letting EAS generate and store a keystore; it is then reused for all future builds. Alternatively you can upload your own keystore and set the password as a secret. Configure or inspect credentials later in the Expo dashboard under your project → Credentials → Android. Never commit keystores or passwords.
    If you already have a Play Store keystore: You can upload it to EAS so that updates to an existing app are signed with the same key. Losing the keystore for a published app can prevent you from ever updating it on the Play Store, so backing it up and/or using EAS to manage it is important.

    4. Running an Android Build

    From the project root:
    “`bash
    npx eas build –platform android –profile development # dev client
    npx eas build –platform android –profile preview # internal
    npx eas build –platform android –profile production # Play Store
    “`
    Use `–platform all` to build Android and iOS in one go. The CLI prints a link to the build page; you can also open Builds in the Expo dashboard.
    Useful flags: `–non-interactive` for CI (no prompts); `–clear-cache` if you suspect a cache issue; `–local` to run the build on your machine instead of EAS (requires Android SDK/Studio locally). You can also pass `–message “Release 1.2.3″` to attach a message to the build for your team.

    5. After the Build

    Builds run on Expo’s servers. Link to the build page is printed in the terminal; you can also open expo.dev → your project → Builds. For internal distribution, EAS provides a link or QR code to download the APK or AAB. For production, download the AAB and upload it to Google Play Console, or run:
    “`bash
    npx eas submit –platform android –profile production
    “`
    Configure the submit profile in `eas.json` under `submit` if you need custom options (e.g. track, rollout fraction). Google Play: For first-time submission you still need to create the app in Play Console and complete store listing; EAS Submit uploads the AAB and can optionally promote to a track (internal, alpha, beta, production).

    Process: iOS Cloud Builds

    1. iOS Config in app.config

    The `ios` block should include:

  • `bundleIdentifier` — Must match the app you create in App Store Connect (e.g. `com.yourcompany.yourapp`).
  • `buildNumber` — Can be managed by EAS when `autoIncrement` is enabled in the build profile.
  • Add any Apple-specific options (e.g. `usesAppleSignIn`, `infoPlist`). Keep sensitive values in env vars and EAS Secrets, not in the repo.
    Simulator vs device: A simulator build runs only in the iOS Simulator (no Apple Developer account or provisioning needed for the build itself). It’s useful for CI, automated tests, or quick checks without a device. Device builds (development, preview, production) require an Apple Developer account and proper provisioning; EAS can generate and store the required certificates and profiles for you.

    2. Build Profiles for iOS

    Use a simulator profile (e.g. `ios.simulator: true`) for fast, device-free testing; preview for internal device testing; production for App Store. Same idea as Android: `distribution` and `environment` control who can install the build and which secrets are injected.

    3. First-Time Setup: Apple Developer and Credentials

    You need an Apple Developer Program membership ($99/year). In App Store Connect, create the app and set the bundle ID to match `app.config`. When you run your first iOS build, EAS will prompt for your Apple ID and can generate and store distribution certificates and provisioning profiles. For internal builds it uses ad-hoc or development provisioning; for production it uses a distribution certificate and App Store profile. You can also upload your own credentials. Manage them in the Expo dashboard under Credentials → iOS. Never commit certificates or provisioning profiles.
    Provisioning in brief: Development and ad-hoc profiles are tied to specific device UDIDs. For internal distribution, testers must register their devices (EAS can help via `eas device:create`). App Store distribution uses a single distribution profile and does not require per-device registration.

    4. Running an iOS Build

    From the project root:
    “`bash
    npx eas build –platform ios –profile ios-simulator # simulator only
    npx eas build –platform ios –profile development # dev client (device)
    npx eas build –platform ios –profile preview # internal
    npx eas build –platform ios –profile production # App Store
    “`
    iOS builds run on macOS workers in the cloud. Progress and logs are on the build page. Simulator builds are typically faster than device builds because they skip code signing and provisioning steps.

    5. After the Build

    For simulator builds, download the artifact and install it in the iOS Simulator. For internal distribution, EAS gives a link; testers may need their device UDIDs registered in the Apple Developer portal—you can use `eas device:create` to simplify that. For production, download the IPA and upload to App Store Connect or run:
    “`bash
    npx eas submit –platform ios –profile production
    “`
    App Store Connect: Ensure the app record exists in App Store Connect with the correct bundle ID. EAS Submit uploads the IPA and can optionally submit for TestFlight or App Store review; you can also upload the IPA manually from the build page.

    Tips and Troubleshooting

  • Build fails with “missing environment variable”: Ensure the profile’s `environment` has the required EAS Secrets set. Run `eas secret:list` and add any missing vars with `eas secret:create`.
  • iOS build fails on credentials: In the dashboard, check Credentials → iOS. Delete invalid or expired certs and let EAS regenerate, or upload your own.
  • Android build fails on signing: Confirm the keystore (and alias/password if you uploaded your own) are set correctly under Credentials → Android.
  • Slow or flaky builds: Use `–clear-cache` sparingly; usually caching helps. If dependencies or native code change often, consider splitting rarely changed layers so cache hits more often.
  • Reproducibility: Always tag or note the git commit (or branch) when sharing a build link; the build page shows the commit so you can match it to source.
coma

Expo EAS simplifies the complexity of building React Native apps by moving the entire build and signing process to the cloud. With a consistent setup across Android and iOS—covering prerequisites, credential management, and build commands—teams can generate reliable builds without maintaining local environments or handling sensitive files manually. Whether you’re creating internal test builds or preparing for store releases, EAS provides a unified, scalable workflow that reduces friction and improves release velocity.
By leveraging EAS Secrets and environment-based configurations, you also ensure that sensitive data remains secure while keeping builds reproducible across teams and CI pipelines. This approach not only minimizes operational overhead but also enables faster, more predictable deployments—making it easier to scale your mobile development process with confidence.

Arun Badole

Arun Badole

Head of Engineering

Connect Now

Arun is VP of Engineering at Mindbowser with over 12 years of experience delivering scalable, compliant healthcare solutions. He specializes in HL7 FHIR, SMART on FHIR, and backend architectures that power real-time clinical and billing workflows.

Arun has led the development of solution accelerators for claims automation, prior auth, and eligibility checks, helping healthcare teams reduce time to market.

His work blends deep technical expertise with domain-driven design to build regulation-ready, interoperable platforms for modern care delivery.

Share This Blog

Read More Similar Blogs

Let’s Transform
Healthcare,
Together.

Partner with us to design, build, and scale digital solutions that drive better outcomes.

Location

5900 Balcones Dr, Ste 100-7286, Austin, TX 78731, United States

Contact form