Expo
Expo Tutorial for Beginners: Setup, Create and Run a React Native App
Learn Expo step by step — install the prerequisites, create your first app, run it on Android, iPhone, an emulator and the web, and build an APK with EAS.
What this tutorial covers
This is a practical, start-to-finish walkthrough of the Expo workflow. By the end you will have created a real project, run it on a phone, an emulator and the web, and produced an installable Android build.
You will work through:
- Installing the prerequisites and checking they work
- Creating a project with
create-expo-app - Starting the development server and opening the app on four different targets
- Understanding when Expo Go is enough and when you need a development build
- Creating an Android development build
- Building an installable APK with EAS Build
- Fixing the problems beginners actually hit
Who this is for: you know some JavaScript and ideally a little React. You do not need any prior Android or iOS experience.
Time required: roughly 20 minutes to a running app; longer if you go through the build sections.
All commands here were checked against the official Expo documentation for SDK 57, which was released on 30 June 2026 and ships React Native 0.86 and React 19.2.
Quick start
If you just want the shortest path from nothing to a running app, this is it:
# 1. Check you have a recent Node.js (SDK 57 needs 22.13 or newer)
node -v
# 2. Create the project
npx create-expo-app@latest my-first-app
# 3. Move into it
cd my-first-app
# 4. Start the development server
npx expo startA QR code appears in your terminal. Install Expo Go from the Play Store or App Store, scan the code, and your app opens on your phone.
The rest of this guide explains what each of those steps actually does, and what to do when one of them does not work.
What is Expo?
Expo is a framework and a set of services built on top of React Native. React Native lets you write mobile apps in JavaScript or TypeScript; Expo removes most of the native tooling work that normally surrounds it.
Concretely, Expo gives you:
- A managed native layer. You do not have to open Android Studio or Xcode to get started.
- A CLI and bundler (
npx expo start) with fast refresh, so saved changes appear on the device almost immediately. - A large library of device APIs — camera, location, notifications, file system, secure storage — that are versioned together so they actually work with each other.
- EAS (Expo Application Services), a cloud build and submission service, so you can produce Android and iOS binaries without maintaining local build machines.
If you have read about libraries versus frameworks and inversion of control, Expo sits firmly on the framework side: it calls your code, owns the build pipeline, and expects you to work inside its conventions. That trade — less control, far less configuration — is the whole point.
Expo vs React Native
This confuses almost every beginner, so it is worth stating plainly: Expo is not an alternative to React Native. It is a framework built on React Native.
| React Native (bare) | Expo | |
|---|---|---|
| Native project files | You manage android/ and ios/ yourself | Generated for you when needed |
| Getting started | Requires Android Studio and/or Xcode up front | Works with only Node.js installed |
| Device APIs | Install and link each library manually | Versioned Expo SDK packages |
| Builds | Local native toolchain | EAS Build in the cloud, or local |
| Escape hatch | You are already there | npx expo prebuild generates native projects |
The important part is that last row. Choosing Expo does not lock you out of native code — when you need it, Expo generates the native projects for you. Most apps never need to.
Prerequisites for Expo development
You need less than you might expect.
Required for every platform:
- Node.js. Use the current LTS release. Expo SDK 57 requires Node.js 22.13 or newer.
- A package manager. npm ships with Node.js; yarn, pnpm and bun all work.
- A phone with Expo Go, or an emulator/simulator.
Only if you want to run a local emulator or simulator:
- Android Studio for the Android emulator (Windows, macOS or Linux)
- Xcode for the iOS simulator (macOS only — there is no supported way to run an iOS simulator on Windows or Linux)
Verify your setup before going further:
node -v
npm -vIf node -v prints something older than v22.13.0, install the current LTS from nodejs.org before continuing. A large share of “it just won’t start” problems trace back to an outdated Node.js.
How to set up Expo
There is no global Expo installation step, and this is the single most out-of-date instruction still circulating in older tutorials. You do not need npm install -g expo-cli. Since SDK 46, the CLI lives inside your project rather than on your machine.
Instead, you invoke the project’s own CLI with npx:
npx expo --versionnpx runs the version of the CLI that belongs to the current project, which means your tooling always matches your SDK version. Outside a project, it fetches the latest on demand.
The only tool you may install globally is the EAS CLI, and only when you reach the build sections later in this guide.
How to create an Expo app
Create a project with create-expo-app:
npx create-expo-app@latest my-first-appIf you want to pin the SDK version explicitly — useful when you are following a guide months later — pass a template:
npx create-expo-app@latest my-first-app --template default@sdk-57The default template includes Expo Router and TypeScript configuration, and gives you a small multi-screen example app to start from.
The project structure
my-first-app/
├── app/ # Your screens — file-based routing lives here
│ ├── _layout.tsx # Root layout, runs before any screen
│ └── index.tsx # The screen shown at "/"
├── assets/ # Images, fonts, icons
├── components/ # Reusable components (not routes)
├── app.json # App config: name, icon, splash screen, plugins
├── package.json # Dependencies and scripts
└── tsconfig.json # TypeScript configurationTwo things surprise people coming from older tutorials:
There is no App.js. The default template uses Expo Router, so the entry point is app/_layout.tsx. Initialisation code that used to live in App.js — providers, fonts, global state — belongs in the root layout now.
Routing is based on file location. A file at app/settings.tsx is reachable at /settings; app/profile/friends.tsx is /profile/friends. Components that are not screens must live outside app/, or the router will treat them as routes.
A minimal screen looks like this:
import { Text, View } from 'react-native';
export default function Index() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Hello Expo</Text>
</View>
);
}Save the file and the change appears on your device within a second or two. That feedback loop is the main reason to use Expo.
Installing packages
Use npx expo install rather than npm install for anything that touches native code:
npx expo install expo-cameraReact Native is not backwards compatible between versions, so packages often need one exact version to match the react-native in your project. npx expo install resolves the correct version for your SDK; plain npm install grabs the newest release, which is frequently the wrong one. For ordinary JavaScript-only dependencies, npm install is fine.
How to run an Expo app
Start the development server from your project directory:
npx expo startThe terminal prints a QR code and a menu of shortcut keys. The server bundles your JavaScript and serves it to whichever client connects — the same server drives every target below.
Leave this running while you work. You only restart it when you change native configuration or install a native package.
Run on a physical Android device
- Install Expo Go from the Google Play Store.
- Make sure the phone and your computer are on the same Wi-Fi network.
- Open Expo Go and scan the QR code from your terminal.
The app downloads the JavaScript bundle and opens. Shake the device to reveal the developer menu.
Run on iPhone
Identical, with one difference: install Expo Go from the App Store and scan the QR code with the built-in Camera app rather than from inside Expo Go. Tap the notification banner that appears.
You do not need a Mac to run your app on a physical iPhone this way. You only need macOS for the iOS simulator and for App Store builds.
Run on an Android emulator
With Android Studio installed and a virtual device created, start the emulator, then press a in the terminal running npx expo start. Expo installs Expo Go into the emulator if it is not already there and opens your project.
Run on an iOS simulator
On macOS with Xcode installed, press i in the same terminal.
Run in a web browser
npx expo start --webYour app opens in the browser using React Native for Web. Most layout and logic carries over; native-only modules do not. Treat web as a bonus target, not a guarantee.
When the QR code will not connect
The QR code approach relies on your phone reaching your computer directly over the local network. Corporate Wi-Fi, guest networks and client isolation all break this. Route the connection through Expo’s tunnel instead:
npx expo start --tunnelThis works across different networks entirely, at the cost of noticeably slower reloads. Use it as a fallback, not a default.
Expo Go vs development builds
Expo Go is a pre-built app that Expo publishes to the app stores. When you scan a QR code, Expo Go loads your JavaScript into its native binary. That is why it starts so fast — and it is also the source of every limitation.
Because the native side of Expo Go is fixed and cannot be changed, only the APIs and libraries already bundled into it are available. According to Expo’s own documentation, the practical consequences are:
- Third-party native libraries do not work. A package like
react-native-firebasefails, because its native code is not inside Expo Go. - Native app configuration cannot be tested. Custom app icons, app names and splash screens will not appear as they will in your real app.
- Remote push notifications are unavailable. Only in-app notifications work.
- App Links and Universal Links are impossible, for the same reason — the native code is immutable.
- One Expo Go build supports exactly one SDK version. Your project’s SDK and the installed Expo Go must match.
A development build solves all of this. It is your own version of Expo Go: a native binary built from your project, including whatever native libraries and configuration you need, with the expo-dev-client package added so it still connects to your development server and still has fast refresh.
| Expo Go | Development build | |
|---|---|---|
| Setup time | Seconds | One build, then reuse it |
| Custom native libraries | No | Yes |
| Native config (icon, splash, name) | No | Yes |
| Remote push notifications | No | Yes |
| Deep links / App Links | No | Yes |
| Fast refresh | Yes | Yes |
Rule of thumb: start in Expo Go. Move to a development build the first time you need a library Expo Go does not include, or the first time you need to see your real app identity. Expo recommends a development build for any app you intend to ship to the stores.
How to create an Android development build
You have two routes: build in the cloud with EAS, or build locally with your own Android toolchain.
With EAS Build (no local Android setup required)
Install the EAS CLI and sign in:
npm install --global eas-cli
eas loginConfigure the project — this creates eas.json:
eas build:configureMake sure the development profile has developmentClient set to true:
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
}
}
}Then build:
eas build --platform android --profile developmentAn Android development build must be an .apk, not an .aab — the default .aab format is for Play Store distribution and cannot be installed directly on a device or emulator. Setting developmentClient: true or distribution: "internal" produces an APK for you.
When the build finishes, scan the QR code EAS prints with your Android camera, open the link, tap Install, and open the downloaded APK. If you are using an emulator, the CLI asks whether to install it there — press y.
After that, install it once and go back to your normal loop: npx expo start, then open your development build instead of Expo Go.
Locally
If you already have Android Studio configured:
npx expo run:androidThis compiles and installs the native binary on your connected device or emulator, then starts Metro. It runs npx expo prebuild automatically first, generating the android/ directory if it does not already exist.
Two things to know before you run it:
- Once
android/exists on disk, it is yours to maintain. Changes you make toapp.jsonno longer flow into it automatically unless you re-run prebuild. - For later iterations where you have only changed JavaScript, use
npx expo start— there is no need to recompile the native app.
How to build an APK with EAS
Android has two distribution formats, and picking the wrong one wastes a build:
- APK — a directly installable package. Use it for testing, internal distribution and sideloading.
- AAB (Android App Bundle) — the format Google Play requires for new apps. It cannot be installed directly on a device.
EAS build profiles map to these roughly as follows:
| Profile | Typical purpose | Default Android output |
|---|---|---|
development | Daily development with expo-dev-client | APK |
preview | Share a testable build with others | APK (when configured) |
production | Store submission | AAB |
To get a shareable APK, add a preview profile to eas.json with buildType set to apk:
{
"build": {
"preview": {
"android": {
"buildType": "apk"
}
}
}
}Then run:
eas build -p android --profile previewEAS gives you a download link when the build finishes. Anyone with that link can install the APK on an Android device — no Play Store involved.
For a Play Store release, leave the production profile to its AAB default:
eas build --platform android --profile productionExpo best practices
A short list of habits that prevent most of the pain:
- Stay on Node.js LTS. Every SDK states a minimum; SDK 57 needs 22.13 or newer.
- Install native packages with
npx expo install. It picks the version that matches your SDK. - Audit your dependencies periodically.
npx expo install --checkreports packages that are on the wrong version;npx expo install --fixcorrects them. - Run
npx expo-doctorwhen something behaves strangely. It diagnoses common project misconfigurations before you start guessing. - Upgrade the SDK deliberately, not package by package. Expo SDK releases are coordinated sets of versions; upgrading
react-nativeon its own will break things. - Test on a real device early. Emulators hide performance problems, gesture behaviour and permission prompts.
- Keep secrets out of the bundle. Anything shipped in your JavaScript is readable by anyone who downloads the app. Use EAS environment variables and keep genuinely sensitive work on a server.
- Do not reach for native code before you need it. Every native dependency you add is configuration you now own.
- Check the version selector when reading the docs. Expo’s documentation is versioned; a command from an SDK three releases back may no longer exist.
Common Expo problems and fixes
The QR code will not connect. Almost always a network problem: the phone and computer are on different networks, or the network isolates clients. Confirm both are on the same Wi-Fi, then fall back to npx expo start --tunnel.
Pressing a does nothing. No emulator is running and none is available. Open Android Studio, create a virtual device in Device Manager, start it, and press a again.
Pressing i does nothing on Windows or Linux. Expected — the iOS simulator requires macOS and Xcode. Use a physical iPhone with Expo Go, or build for iOS through EAS.
A library crashes or is “not available” in Expo Go. The library needs native code that Expo Go does not contain. This is the signal to create a development build.
Dependency version mismatch warnings. Run npx expo install --check to see what is wrong, then npx expo install --fix. Avoid installing native packages with plain npm install.
Stale or impossible-looking bundler errors. Metro caches transformations aggressively. Restart with a cleared cache:
npx expo start --clearIf that is not enough, remove node_modules, reinstall, and start again with --clear.
Your icon or splash screen has not changed. If you are testing in Expo Go, it never will — those are native assets. You need a development build to see them.
EAS build fails on configuration. Re-run eas build:configure and confirm the profile you are invoking actually exists in eas.json under build.
Deployment basics
Once your app is worth shipping:
Android. Produce an AAB with the production profile and upload it to the Google Play Console. EAS can also submit it for you.
iOS. Build for iOS through EAS and upload via App Store Connect. You need an Apple Developer account; you do not necessarily need a Mac, since EAS builds in the cloud.
Web. Export a static site and host it anywhere:
npx expo export --platform webConclusion
The Expo workflow is short once you see it whole: install Node.js, run npx create-expo-app@latest, run npx expo start, and open the app in Expo Go. That is genuinely the whole loop for the first several days of a project.
The one decision that matters early is Expo Go versus a development build. Expo Go is the fastest way to see something running, and it is the right default. The moment you need a native library, a custom icon, or push notifications, you build your own client once and carry on exactly as before.
From here, the highest-value next steps are learning Expo Router properly — layouts, nested routes and navigation — and building something small enough to finish. A notes app or a weather app will teach you more than any amount of further reading.
Reference
Building Mobile Applications Using Expo (Beginner-Friendly Guide) was originally published in GoPenAI on Medium. This version has been substantially rewritten and updated for Expo SDK 57.