Shipping & Release· 7 min read

EAS Build Explained: Profiles, Credentials, and What It Costs

EAS Build explained for 2026: build profiles in eas.json, managed credentials, local builds, versioning, and what Expo's plans and per-build prices cost.

By

Full-Stack, Mobile & AI Engineer

Before Expo's cloud build service, shipping a React Native app meant owning a Mac build machine, keeping Xcode and Android tooling in sync, and guarding a folder of certificates that only one person understood. EAS Build, Expo's cloud service for compiling and signing iOS and Android binaries, replaces most of that with a configuration file and a command, and it works for bare React Native projects as well as Expo ones.

This guide explains how it works in practice: the build profiles in eas.json, how credentials are handled, how to keep version numbers straight, when to build locally, and what it actually costs in 2026.

Key takeaways

  • Your iOS and Android apps compile in Expo's cloud, so you don't need a Mac to ship iOS.
  • Profiles in eas.json (usually development, preview and production) decide what kind of build you get and where it goes.
  • EAS can create and store your signing credentials: iOS certificates and provisioning profiles, and Android keystores.
  • Use remote versioning with autoIncrement so build numbers never collide.
  • Cost (October 2026): a Free plan with up to 15 iOS and 15 Android builds a month on a low-priority queue, a $19/month Starter plan with $45 of build credit, and per-build prices of $1 to $4 beyond the credit.

How a cloud build works

When you run eas build, the CLI uploads your project to Expo's build servers. A fresh virtual machine installs your dependencies, runs prebuild if you use Continuous Native Generation, compiles the native app with Xcode or Gradle, signs it with your credentials and gives you a downloadable artifact: an .ipa for iOS, an .aab or .apk for Android.

You don't need an Apple Developer account for iOS simulator builds (set "ios": { "simulator": true } in a profile); builds for real iPhones and the App Store do need one. Nothing about this locks you in. The output is a normal signed app, and you can always build the same project locally.

Build profiles in eas.json

Profiles are named recipes. A typical setup:

{
  "cli": { "appVersionSource": "remote" },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "channel": "preview"
    },
    "production": {
      "autoIncrement": true,
      "channel": "production"
    }
  },
  "submit": { "production": {} }
}
ProfileUsed forWho installs it
developmentA development build with your native code and dev toolsYour team, while building features
previewA release-like build for testingTesters and clients, via internal distribution
productionThe store buildApp Store and Google Play

The channel field connects each build to an EAS Update channel, so over-the-air updates reach the right builds.

Credentials: who holds the keys

On the first iOS build, EAS asks to sign in to your Apple account and can create the distribution certificate and provisioning profile for you. On Android, it can generate an upload keystore. Both are stored encrypted on Expo's servers and reused for every build.

You can also bring your own credentials with a credentials.json file, or manage them with eas credentials. Either way:

  • Keep the Apple and Google accounts in your company's name.
  • Download a backup of the Android upload keystore and store it somewhere safe.
  • Enable Play App Signing, so a lost upload key can be reset.

Version numbers without the headaches

Every store upload needs a new build number (iOS) or versionCode (Android). With "appVersionSource": "remote" and "autoIncrement": true on the production profile, EAS stores and increments those numbers for you, so two developers building on the same day never upload a duplicate. You still set the user-facing version (like 1.4.0) yourself when a release deserves it.

Building locally

eas build --platform android --profile production --local

--local runs the same build process on your own machine (iOS builds still need a Mac). It's useful for debugging a build failure, for strict environments where code can't leave your network, or when you've used up your cloud builds for the month.

Node, Xcode and environment variables

Each build profile can pin the toolchain, so a build behaves the same next month as it does today:

  • node sets the Node.js version for the build, for example "node": "22.12.0".
  • image (under ios or android) picks the build image, which determines the Xcode or Android tooling version. "image": "latest" follows Expo's newest image; pin a specific image when you need a fixed Xcode version, and check Expo's build infrastructure page for the current list.
  • resourceClass chooses medium or large workers (large isn't available on the free plan).
  • environment (development, preview or production) decides which EAS environment variables the build receives.

Environment variables live in EAS rather than in your repository:

eas env:set --name EXPO_PUBLIC_API_URL --value https://api.example.com --environment production --visibility plaintext

Each variable is plain text, sensitive (hidden in build logs) or secret (never readable outside Expo's servers). Files such as Firebase's google-services.json can be uploaded as file variables; the build receives a file path, which you reference from app.config.js:

export default {
  expo: {
    android: { googleServicesFile: process.env.GOOGLE_SERVICES_JSON ?? "./google-services.json" },
  },
};

One caution from Expo's own documentation: anything that ends up in client code is public, whatever its visibility setting. Keep real secrets on your server.

Hooks, CI and auto-submit

Lifecycle hooks are package.json scripts that EAS runs at fixed points: eas-build-pre-install, eas-build-post-install (after install, prebuild and, on iOS, pod install), eas-build-on-success, eas-build-on-error, eas-build-on-complete and eas-build-on-cancel. They're the place for steps like generating a config file or notifying a chat channel when a build fails.

CI builds use the same CLI without prompts. In GitHub Actions, add an EXPO_TOKEN secret, then:

eas build --platform all --profile production --non-interactive --no-wait

--no-wait returns as soon as the build is queued; watch its status on the Expo dashboard or with eas build:list.

Auto-submit sends the finished build straight to the stores: eas build --platform ios --profile production --auto-submit uploads the iOS build to App Store Connect, where it appears in TestFlight once Apple finishes processing it.

EAS Build vs Expo Go vs building in Xcode

Expo GoEAS development buildLocal Xcode or Android Studio build
What it isA ready-made app from the stores that runs your JavaScriptYour own app, with your native code and dev toolsA native build on your machine
Custom native codeOnly the modules bundled into Expo GoYesYes
Needs a Mac for iOSNoNo (cloud)Yes
SigningNot neededManaged by EASManual or Xcode-managed
Best forQuick experiments and learningDay-to-day development and testingDebugging native build problems

Expo Go supports one SDK version at a time and, since September 2026, asks you to sign in to an Expo account. As soon as a project needs a library with its own native code, development builds are the better default.

What it costs (October 2026)

PlanPriceBuildsQueue
Free$0Up to 15 Android and 15 iOS builds a monthLow priority (Expo warns of 90+ minute waits at peak)
Starter$19/month plus usage$45 of build credit, then pay per buildHigh priority
Production$199/month plus usage$225 of build credit, then pay per buildHigh priority, 2 concurrent builds
EnterpriseCustomFrom $1,000 of build creditHigh priority, 5 concurrent builds

Beyond the included credit, builds cost $1 (Android, medium worker) to $2 (large) and $2 (iOS, medium) to $4 (large). For a small team shipping weekly, Starter usually covers it. Prices change, so check Expo's pricing page before you budget.

From the field: Expo's build and submit services are part of the release path I own on the apps I ship, alongside EAS Update for over-the-air hotfixes and Fastlane with GitHub Actions where a project needs its own pipeline. The biggest win isn't the cloud machines. It's that the whole release process lives in a config file anyone on the team can read.

Common build failures and fixes

SymptomLikely causeFix
Build fails during pod installNative dependency version conflictsAlign versions with npx expo install --fix; check the library's iOS requirements
Android build runs out of memoryLarge project on a medium workerUse a large worker in the profile, or trim dependencies
Works locally, fails on EASMissing environment variables or secretsAdd them as EAS environment variables for that profile
Upload rejected for duplicate build numberLocal versioning out of syncSwitch to remote versioning with autoIncrement
App crashes on launch, dev build fineRelease-only issue (Hermes bytecode, missing config)Test a preview build before every production build

FAQ

Is EAS Build free?

There's a free plan with up to 15 iOS and 15 Android builds a month on a low-priority queue, which can be slow at busy times. Paid plans start at $19 a month with build credit and priority builds, and you can always build locally for free.

Do I need a Mac to build an iOS app with Expo?

Not if you build in Expo's cloud, which compiles iOS apps for you. You need a Mac only to build iOS locally (including eas build --local for iOS) or to run the iOS simulator.

Can I use EAS Build with a bare React Native project?

Yes. It works with bare projects that keep their own ios and android folders, as well as projects that use Expo's Continuous Native Generation. Add an eas.json and run eas build.

What's the difference between EAS Build and EAS Update?

A build creates full native app binaries that go through store review. EAS Update ships JavaScript and asset changes over the air to builds that are already installed, without a new store release, as long as the native code hasn't changed.

Next steps

If your builds are slow, fragile or depend on one person's laptop, I can set up EAS (or your own CI) so a release is one command anyone on the team can run. Get in touch, or see my services.

Sources

Bhuwanesh Sisodia

Bhuwanesh Sisodia

Full-Stack, Mobile & AI Engineer

Bhuwanesh Sisodia is a Full-Stack, Mobile & AI Engineer based in Mumbai, with 7+ years of experience and 50+ apps shipped to the App Store and Google Play. He works independently with startups and product teams worldwide.

About meGitHubLinkedInX

Related