Chapter 2: Setting up your environment
A working Expo development environment takes about 30 minutes to set up on macOS and roughly the same on Windows or Linux - with one important difference on the iOS side that this chapter explains honestly. By the end, you will have a development build running on a physical device, an Apple Developer account (if targeting iOS), and an understanding of what runs where and why.
Learning objectives
After this chapter you will be able to:
- Install Node.js 22.13+ and verify the Expo toolchain
- Explain why iOS development requires a Mac and what Windows or Linux users should do instead
- Set up Xcode (macOS) or Android Studio (all platforms)
- Enroll in the Apple Developer Program and create the necessary identifiers
- Install
expo-dev-clientand create your first development build - Configure
eas.jsonwith development, preview, and production profiles - Run your project on a physical device
Why this matters
Every chapter after this one assumes you have a working development build on your phone. Chapters on widgets, in-app purchases, push notifications, and store submission all require a custom build with native code - none of them work in Expo Go. Spending 30 minutes on setup today avoids hours of environment debugging scattered across the rest of the handbook.
macOS and iOS: the honest explanation
iOS apps must be compiled with Xcode. Xcode runs only on macOS. This is Apple’s architecture and has been since 2008 - it is not Expo’s limitation, it is a platform constraint every iOS developer faces.
If you own a Mac, install Xcode and proceed to the local setup section below. If you do not, here is what changes:
You can still build iOS apps from Windows or Linux. EAS Build provides cloud macOS workers - Mac mini hosts running macOS Tahoe 26.4 with Xcode 26.4 - that compile your app, sign it, and return a binary you can install on a physical device or upload to TestFlight. The workflow:
- Write all your JavaScript and TypeScript on your Windows or Linux machine. Everything works: Metro bundler, Expo Router, styling, state management, all the JS-level development cycle.
- When you need a native build (new native dependency, code signing,
store submission), run
eas build --platform iosin your terminal. Expo uploads your project to the cloud, compiles it on a macOS worker, and returns the result. - Install the build on your device via a QR code, a direct download link, or TestFlight. Test it, iterate, and push the next build when native code changes.
- You can also run a development build from the cloud - the
expo-dev-clientlauncher connects your cloud-built binary to your local Metro server over your network.
What you lose without a Mac: the iOS simulator (no
Xcode = no simulator), local native debugging (you cannot step through
Swift code in Xcode), and the ability to run
npx expo run:ios locally. You compensate by testing on
physical devices and using EAS Build’s cloud infrastructure.
What you lose without an Apple Developer account ($99/year): everything on iOS. You cannot code-sign an app, run it on a physical device beyond a 7-day personal team provisional, upload to TestFlight, or submit to the App Store. If your product is iOS-only, the developer account is not optional.
Android has none of these restrictions. You can build, sign, and publish to Google Play from any operating system with no annual developer fee beyond the one-time $25 Google Play registration.
Step 1: Node.js and the Expo CLI
Expo SDK 57 requires Node.js 22.13 or higher. Check your current version:
node --versionIf the output is below v22.13.0, install the latest LTS from
nodejs.org, or use a version manager. On macOS,
brew install node@22 works. On Windows, use the official
installer. On Linux, use nvm:
nvm install 22
nvm use 22
node --version # should be v22.x or higherWith Node.js in place, test the Expo CLI. The
create-expo-app command is the starting point for every new
project:
npx create-expo-app@latest --template default@sdk-57If this command completes without errors, your Node.js and network are correctly configured. You do not need to keep the project it creates - we will start fresh in the next step.
Step 2: Platform-specific tooling
macOS: Xcode
Install Xcode from the Mac App Store. It is free. The download is large (roughly 12 GB) and takes a while. Start it now and continue reading.
After installation, open Xcode once to accept the license agreement and let it install additional components. Then install the Command Line Tools:
xcode-select --installVerify the installation:
xcodebuild -version
xcrun simctl list devices | grep "iPhone"You should see Xcode 26.4 or later and a list of iPhone simulators. If you see an earlier version, update from the App Store - Expo SDK 57 requires Xcode 26.4+.
Windows: WSL2
Expo tooling works best in a Unix-like environment. On Windows, install WSL2 (Windows Subsystem for Linux) with Ubuntu. Follow Microsoft’s setup guide at https://learn.microsoft.com/en-us/windows/wsl/install.
Once WSL2 is running Ubuntu, install Node.js inside WSL using nvm as described above. All terminal commands in this handbook should run inside WSL Ubuntu, not PowerShell or Command Prompt.
Android (all platforms)
For Android development, install Android Studio. It is available for macOS, Windows, and Linux at https://developer.android.com/studio.
During installation, accept the default SDK components. After installation, open Android Studio, go to SDK Manager (Configure → SDK Manager), and ensure the following are installed:
- Android SDK Platform 36 (matching Expo SDK 57’s compileSdkVersion)
- Android SDK Build-Tools
- Android Emulator
Then create an Android Virtual Device (AVD) through the AVD Manager. Pick a recent device definition (Pixel 8 or similar) with a recent system image (API 36+).
Add the Android SDK location to your shell profile. On macOS or
Linux, add to ~/.zshrc or ~/.bashrc:
export ANDROID_HOME=$HOME/Library/Android/sdk # macOS
export ANDROID_HOME=$HOME/Android/Sdk # Linux
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-toolsIf you plan to use EAS Build for Android (which handles the build environment in the cloud), Android Studio and the SDK are optional. You can skip the local Android setup and rely entirely on cloud builds. The tradeoff: you cannot run the Android emulator locally, and you cannot test Android builds without uploading to EAS first.
Step 3: Apple Developer Program
The Apple Developer Program costs $99 per year. It is required for: - Running an iOS build on a physical device for more than 7 days - Distributing via TestFlight - Submitting to the App Store - Sending push notifications via APNs - Setting up in-app purchases
Enroll at https://developer.apple.com/programs/. The enrollment process takes a few minutes for individuals, longer for organizations (Apple may request D-U-N-S verification). Have your Apple ID, a payment method, and (for organizations) legal entity documentation ready.
After enrollment, log into the Apple Developer portal and configure these items. They are prerequisites for later chapters and take time to set up:
App ID. Go to Certificates, Identifiers & Profiles → Identifiers. Create an App ID for your project. Use an Explicit App ID (not Wildcard) - explicit IDs are required for push notifications, in-app purchases, and app groups.
APNs Key. Go to Keys → Create a Key. Check “Apple Push Notifications service (APNs).” Download the
.p8file. You get one download - store it securely. This key is used for push notifications (Chapter 10).Developer API Key. Go to Keys → Create a Key. Check “Developer Relations.” Download and store the
.p8file. EAS Build uses this to manage your code signing credentials automatically.
You do not need provisioning profiles or certificates manually - EAS
Build creates and manages them for you when you run
eas credentials. But the identifiers above must exist
first.
Step 4: Create the project
Create the handbook’s companion project:
npx create-expo-app@latest expo-mobile-guide --template default@sdk-57
cd expo-mobile-guideThe default template includes Expo Router, TypeScript, and a basic screen structure. You will expand it throughout the handbook.
Step 5: Install expo-dev-client and create the first build
Expo Go will not work for this handbook - we use native libraries throughout. Install the development client:
npx expo install expo-dev-clientThe dev client adds a launcher UI to your app. When you open the dev build on your device, it shows a screen where you enter your local Metro server URL. It also adds an enhanced dev menu (shake gesture), network inspector, and EAS Update testing UI.
Set up EAS
EAS (Expo Application Services) is Expo’s cloud platform. Install the CLI and log in:
npm install -g eas-cli
eas loginYou will need an Expo account. Create one at https://expo.dev/signup if you do not have one already.
Configure eas.json
eas.json defines build profiles. Create it with:
eas build:configureThe generated file has a preview profile by default. Replace it with three profiles:
{
"cli": {
"version": ">= 16.0.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"android": {
"buildType": "apk"
},
"ios": {
"simulator": false
}
},
"preview": {
"distribution": "internal",
"android": {
"buildType": "apk"
},
"ios": {
"simulator": false
}
},
"production": {
"autoIncrement": true,
"android": {
"buildType": "app-bundle"
}
}
},
"submit": {
"production": {
"android": {
"track": "internal"
}
}
}
}The three profiles serve different purposes:
- development: Debuggable build. Includes
expo-dev-client. Connects to your local Metro server. Use this for daily development. - preview: Release build without optimizations disabled. Suitable for TestFlight and internal testing. Can include dev client for testing teams.
- production: Release build with optimizations
enabled. For App Store and Google Play submission. The
autoIncrementflag bumps the build number automatically for each release.
Configure app.json for the build
Open app.json and ensure the following fields are
set:
{
"expo": {
"name": "Expo Mobile Guide",
"slug": "expo-mobile-guide",
"scheme": "expo-mobile-guide",
"ios": {
"bundleIdentifier": "com.yourname.expomobileguide",
"supportsTablet": true
},
"android": {
"package": "com.yourname.expomobileguide",
"adaptiveIcon": {
"backgroundColor": "#ffffff"
}
},
"plugins": [
"expo-router",
"expo-dev-client"
]
}
}Change com.yourname to your actual reverse-domain
identifier. The bundleIdentifier on iOS must match the App
ID you created in the Apple Developer portal.
Build and install
Run your first development build. For iOS:
eas build --platform ios --profile developmentFor Android:
eas build --platform android --profile developmentThe first build takes 10 to 20 minutes. Subsequent builds are faster - EAS caches dependencies and native projects. When the build completes, EAS prints a QR code. Scan it with your phone’s camera (iOS) or Expo Go app (Android) to install the build.
Once installed, run the Metro dev server:
npx expo start --dev-clientOpen the dev build on your device. The launcher screen appears. Enter your computer’s local IP address (shown in the terminal) and tap Connect. Your project loads with the same fast-refresh cycle as Expo Go, but with all your native dependencies available.
Step 6: Environment variables
Expo handles environment variables at two levels: client-safe and build-time.
Client-safe variables use the
EXPO_PUBLIC_ prefix. These are bundled into your JavaScript
and visible to anyone who inspects the bundle. Use them for
non-sensitive configuration like API base URLs:
EXPO_PUBLIC_API_URL=https://api.example.comAccess them in your code via
process.env.EXPO_PUBLIC_API_URL or through
Constants.expoConfig.extra if you prefer explicit
import.
Build-time secrets use EAS environment variables. These are encrypted, stored on Expo’s servers, and injected during the build. Use them for API keys, signing credentials, and anything sensitive:
eas env:push --scope projectThis opens an interactive editor where you set variables like
API_SECRET_KEY, SENTRY_AUTH_TOKEN, and
REVENUECAT_API_KEY. These are available as
process.env.VARIABLE_NAME in your app at runtime.
Never commit secrets to your repository. Never use
EXPO_PUBLIC_ for API keys, tokens, or anything that grants
access.
Verification checklist
Before moving to Chapter 3, confirm each of these:
-
node --versionis 22.13 or higher -
npx create-expo-appcreates a project without errors -
Xcode is installed and
xcodebuild -versionreturns 26.4+ (macOS only) - Apple Developer account is enrolled and an App ID exists (iOS only)
- APNs key and Developer API key are downloaded and stored (iOS only)
-
eas loginsucceeds -
eas.jsonhas development, preview, and production profiles -
A development build completed successfully via
eas build --profile development - The dev build connects to Metro and loads your project on a physical device
If any check fails, do not proceed. The rest of the handbook depends on a working development environment. Most setup failures come from three sources: outdated Node.js, missing Apple Developer enrollment, or an incomplete Xcode installation.
Key takeaways
- iOS development requires macOS for local Xcode builds. EAS Build provides cloud macOS workers for Windows and Linux users. You can do JS-level development from any OS and use cloud builds for iOS binaries.
- The Apple Developer Program ($99/year) is required for iOS distribution beyond a 7-day temporary provisioning window.
- Development builds (
expo-dev-client) replace Expo Go for production work. Create one at the start of every project. - Three build profiles in
eas.json- development, preview, production - cover the full testing-to-release pipeline. - Use
EXPO_PUBLIC_for client-safe config and EAS environment variables for secrets. Never commit secrets.
Common pitfalls
- Waiting to set up the Apple Developer account. Enrollment can take hours for organizations (D-U-N-S verification). Individuals can enroll in minutes, but start early anyway - the chapter on App Store submission assumes the account exists.
- Skipping the APNs key creation. You cannot add push notifications later without a new provisioning profile. Create the key now even if you do not plan to use notifications immediately.
- Using Expo Go past Chapter 2. Every chapter after this one adds native dependencies. Expo Go does not have them. Debugging “why does this not work in Expo Go” wastes time - use a development build from the start.
- Not verifying the dev build connects to Metro. A build that installs but does not connect to your dev server is a network configuration issue. Check your firewall, ensure your phone and computer are on the same Wi-Fi network, and verify the local IP address in the launcher.
Further reading
- Expo environment setup guide: https://docs.expo.dev/get-started/set-up-your-environment/
- Development builds: https://docs.expo.dev/develop/development-builds/introduction/
- EAS Build introduction: https://docs.expo.dev/build/introduction/
- Apple Developer Program: https://developer.apple.com/programs/
- Node.js downloads: https://nodejs.org
- Android Studio: https://developer.android.com/studio
Checkpoint exercise
Create the project, run a development build, and get it loading on
your physical device. If you are on macOS, verify the iOS simulator also
works with npx expo start (Expo Go is fine for this test
since no native modules are involved yet). If you are on Windows or
Linux, verify Android works either locally or via EAS Build cloud. Take
a screenshot of the app running on your device and note the time it took
from create-expo-app to a working build.