CalcSnippets Search
Mobile 3 min read

Expo Local Builds on macOS: How to Run iOS and Android Without Waiting on Cloud Builds

A practical Expo local development guide for macOS that covers prerequisites, device and simulator startup, local native runs, and the workflow differences between Expo Go, development builds, and cloud builds.

Why this topic confuses people: Expo is often introduced through the happy path, where everything looks instant. The moment native modules, simulators, or device-specific behavior enter the picture, developers realize they need a more honest workflow.

The three Expo modes people blur together

When people say “I am using Expo,” they might mean very different things:

  1. Expo Go
  2. a local development build
  3. a cloud build through EAS

Those are not interchangeable. If you do not separate them, you will keep expecting one mode to solve another mode’s problem.

What you need on macOS

For iOS work:

  • Xcode
  • Xcode command line tools
  • a working Simulator

For Android work:

  • Android Studio or command-line tools
  • a working emulator or device

And for the project itself:

npx expo --version

If this fails, fix Node and package setup before touching mobile tooling.

Start from a clean project command

For a project already set up:

npx expo start

That is fine for JavaScript-level iteration, especially with Expo Go. But once you need native code or plugin-backed features, you should move to development builds.

Run iOS locally

If the project supports native local execution:

npx expo run:ios

This command generates and runs the native iOS project as needed. It is the point where Expo stops feeling like a pure JavaScript abstraction and starts acting like a real app pipeline.

Run Android locally

npx expo run:android

As with iOS, this is the workflow you reach for when Expo Go is not enough.

Why developers get stuck here

Usually one of these is the real problem:

  1. the simulator or emulator is not actually available
  2. native prerequisites are incomplete
  3. the app depends on something Expo Go cannot represent
  4. cached or half-generated native state is confusing the run

That third point is the important one. Expo Go is great, but it is not the same as “native support for everything.”

When cloud builds are the wrong first move

Developers often jump to EAS because local native setup feels annoying. That is understandable, but it is a bad debugging habit. If the app cannot run locally with the tooling you control, cloud builds usually make the feedback loop slower, not smarter.

A local build gives you faster iteration on real device behavior. That matters much more than saving a few setup steps.

A practical workflow split

Use npx expo start when:

  • UI iteration is mostly JavaScript-only
  • Expo Go is enough
  • you want the fastest non-native loop

Use npx expo run:ios or npx expo run:android when:

  • native modules matter
  • permissions or device behavior matter
  • the app needs a real development build

That separation is what keeps Expo productive instead of mysterious.

Final recommendation

Do not ask Expo to be one thing all the time. Use the fast JavaScript path when it fits, then move to local native runs as soon as the app crosses that line. Developers get frustrated with Expo mostly when they keep pretending Expo Go and real native execution are the same workflow.

Sources

Keep reading

Related guides