How to Build and Test iOS Apps on a Physical Phone: Expo EAS and Apple TestFlight (Part 1/5)
Cathy Lai

Cathy Lai @cathylai

About: React Native developer with a background in large-scale e-commerce and SaaS systems.

Location:
Auckland, New Zealand
Joined:
Aug 6, 2022

How to Build and Test iOS Apps on a Physical Phone: Expo EAS and Apple TestFlight (Part 1/5)

Publish Date: Feb 10
4 2

So you have turned a bright idea into a release-ready iOS app, time to test it properly by friends and family on their physical phones!

This 5-part article will explain how we can go from an app created on our PC/laptop to the Apple App Store, via an app called TestFlight which enables external testers to use the preview version of our app.

The analogy (from this article)

  • We (the developers): The brand owners
  • Our app: The product
  • EAS (Expo Application Service): The manufacturer + logistics company
  • Apple App Store: The supermarket
  • TestFlight: supermarket's tasting room. The product (our app) must be "registered" first before it can be entered in this room

Part 1 — Identity & Setup

This part connects your local project, Expo, and Apple so they all agree on your app’s identity.

Step 1/7 : Install and log in to EAS

npm i -g eas-cli
eas login
Enter fullscreen mode Exit fullscreen mode

Step 2/7 : Initialize EAS in your project

eas init
Enter fullscreen mode Exit fullscreen mode

This links your repo to an Expo project.

Step 3/7 : Verify app.json (or app.config.*)

Make sure these two things are correct:

  • ios.bundleIdentifier This must match what you’ll use in App Store Connect.
"expo": {
    "name": "oauth-pro2",
    "ios": {
        "bundleIdentifier": "com.cathyapp1234.oauthpro2",
     },
}
Enter fullscreen mode Exit fullscreen mode

  • extra.eas.projectId This links your local project to Expo EAS.
  "expo": {
     "extra" : {
        "eas": {
           "projectId": "a31c0453-d16e-4818-aa19-d380a5bfc5d4"
        }
      }
  }
Enter fullscreen mode Exit fullscreen mode

Step 4/7: Define build Profiles in eas.json

Regardless of a build profile (eg "preview" or "production"), there are two types of builds:

  • Ad Hoc Build, binary is on Expo :
 "distribution": "internal"
Enter fullscreen mode Exit fullscreen mode
  • Signed and is permitted to be on the App Store
 "distribution": "store"
Enter fullscreen mode Exit fullscreen mode

We are building the latter so we can download it via TestFlight.

Also, it is useful to auto increment the build number with every EAS build

 "autoIncrement": true,
Enter fullscreen mode Exit fullscreen mode

The eas.json:

{
  "build": {
    "preview": {
      "distribution": "store", 
      "channel": "preview",     
      "autoIncrement": true,
    },

  }
}
Enter fullscreen mode Exit fullscreen mode

The convention is to use EAS remote build number instead of keeping tracks of it ourselves:

{
  "cli": {
    "appVersionSource": "remote"
  }
},
Enter fullscreen mode Exit fullscreen mode

In this system, build number is a single counter tied to your Project ID and Platform (iOS), not to a specific build profile. This means, both

eas build --profile preview
Enter fullscreen mode Exit fullscreen mode

and

eas build --profile production
Enter fullscreen mode Exit fullscreen mode

will both increase the same build number.

Step 5/7: Add the Corresponding submit Profiles

Make sure the entries are available, even if empty. Otherwise the build will give errors.

{
  "submit": {
    "production": {},
    "preview": {}
  }
}
Enter fullscreen mode Exit fullscreen mode

Final eas.json can be found in this GitHub repository.

Step 6/7: Channels and OTA (Over the Air Updates)

Since we have specify different channels for each build profile, we can send code updates (bug fixes, small changes) over the air (OTA) via the channels to phones that already have the app installed, without having to resubmit to the App Store.
You can choose to skip this step, but EAS will give a warning.

Run the followings for this function

npx expo install expo-updates
eas update:configure
Enter fullscreen mode Exit fullscreen mode

Step 7/7: Check into remote GitHub

git push origin main
Enter fullscreen mode Exit fullscreen mode

Next, we are ready to build our app!

Prefer to Watch a Video?

Comments 2 total

  • Bhavin Sheth
    Bhavin ShethFeb 10, 2026

    This is a really clear breakdown — the supermarket/TestFlight analogy makes a confusing process click instantly 👍
    I like how you focus on identity + setup first; that’s exactly where most Expo/EAS issues come from. Looking forward to Part 2, especially the TestFlight side of things.

    • Cathy Lai
      Cathy LaiFeb 11, 2026

      Thanks Bhavin!

      It took me many Q n A sessions with ChatGPT and Gemini and practices before I can understand everything. Hard to believe why everything is so confusing..!

      Part 2/3 should be a bit easier now. 😊

Add comment