Why do current Expo projects run npx expo start from the local CLI inside the expo package instead of a globally installed expo-cli?
answer
- versioned with the project
- @expo/cli ships inside expo
- old global expo-cli deprecated
- old commands point to replacements
- EAS CLI is the global exception
basics
~20 sThe Expo CLI now ships inside each project's expo package, so npx expo start always runs the CLI version that matches that project's SDK. The old global expo-cli is deprecated, and its retired commands point to replacements.
solid answer
~40 s`@expo/cli` is installed with the `expo` package, so each project carries a CLI **versioned** with its SDK. `npx expo start` resolves that local copy, which means two projects on different SDKs never fight over one global install, and CI uses exactly the CLI the lockfile pins. The globally installed `expo-cli` is deprecated. Retired commands point to their replacements: `expo init` became `npx create-expo-app`, `expo eject` became `npx expo prebuild`, `expo publish` became `eas update`, `expo build:ios` became `eas build -p ios`, and `expo doctor` became `npx expo-doctor`. EAS CLI is the one tool still installed globally, because it talks to cloud services rather than the project's bundler. The dev server itself opens a development build if `expo-dev-client` is installed and Expo Go otherwise, with `--dev-client` or `--go` to force one.
code
bash · 10 lines# Runs the CLI version pinned in this project's node_modules
npx expo start
# Force the launch target, clear the bundler cache
npx expo start --dev-client --clear
# Retired global commands and their replacements
npx create-expo-app@latest my-app # was: expo init
npx expo prebuild # was: expo eject
eas update # was: expo publishgo deeper
Know to run npx expo start in the project, not a global expo command, and that it opens Expo Go or a development build.
Explain that @expo/cli is versioned with the expo package and name the replacements for init, eject, publish and build.
Spot stale global tooling in onboarding docs and CI scripts, and make sure CI runs the CLI pinned by the lockfile.
Treat tooling pinned per project as the rule, so SDK upgrades move the CLI with them and machines never drift apart.
## Two CLIs, two eras Older Expo projects used **`expo-cli`**, a package installed **globally** on the developer's machine. One global binary served every project on that machine, whatever SDK each used. Current projects use the **local Expo CLI**, the `@expo/cli` package, which is installed with the `expo` package inside each project. The Expo glossary calls it the "Versioned Expo CLI" and describes the global `expo-cli` as deprecated. You run it through the package runner, `npx expo <command>` (or `yarn expo`, and so on), which resolves the copy in the project's `node_modules`. ## Why a versioned CLI is better - **The CLI matches the SDK.** Bundling, config resolution and prebuild behaviour change between SDK releases. A CLI that ships with `expo` always understands the project it is in. - **No machine-wide drift.** Two projects on different SDKs each get their own CLI; nobody has to reinstall a global tool to switch. - **Reproducible CI.** The lockfile pins the CLI, so a build server runs exactly what developers run. - **Upgrades move together.** Upgrading `expo` upgrades its CLI in the same step. ## What happened to the old commands The local CLI prints a pointer when you type a command it no longer supports: | Old global command | Replacement | |---|---| | `expo init` | `npx create-expo-app` | | `expo eject` | `npx expo prebuild` | | `expo publish` | `eas update` | | `expo build:ios` / `expo build:android` | `eas build -p ios` / `eas build -p android` | | `expo doctor` | `npx expo-doctor` | | `expo upgrade` | the SDK upgrade guide | Build, credentials and publishing commands moved to **EAS CLI**, which is still installed globally because it drives Expo's cloud services rather than the project's local bundler. ## The dev server command `npx expo start` (or just `npx expo`) starts the development server, Metro by default, on port 8081, and shows the Terminal UI with a QR code and shortcuts. Points worth knowing: 1. **Launch target.** It opens the app in a **development build** if `expo-dev-client` is installed, otherwise in **Expo Go**. `--dev-client` or `--go` forces one, and pressing `s` switches at runtime. 2. **Connection.** LAN by default; `--localhost` restricts it and `--tunnel` exposes it through a tunnel when the device cannot reach your network. 3. **Platforms.** `--android`, `--ios` and `--web` (or `a`, `i`, `w` in the Terminal UI) open a target straight away. 4. **Cache.** `--clear` (alias `--reset-cache`) clears the bundler cache when stale transforms are suspected. ## Onboarding a project that still assumes the global CLI Older repositories often carry README steps and CI scripts written for the global tool. A clean migration: 1. Remove the global `expo-cli` from developer machines and CI images, so nothing resolves to it by accident. 2. Rewrite scripts to use `npx expo …` (or the package manager's equivalent) so they run the project's pinned CLI. 3. Replace retired commands using the table above; `expo publish` and `expo build:*` calls move to EAS CLI. 4. Upgrade the `expo` package to a supported SDK, since the local CLI ships with it. 5. Update the onboarding docs in the same change, so new joiners never learn the old commands. ## Common mistakes - Keeping an old global `expo-cli` on the `PATH` and typing `expo start` without `npx`: the command can resolve to the deprecated global binary instead of the project's CLI. - Following an old tutorial's `expo eject` or `expo publish`: both are retired, with the replacements above. - Expecting `npx expo build:ios` to exist because an old tutorial used `expo build:ios`: builds live in EAS CLI, as `eas build -p ios`. ## Interview framing The question tests whether a candidate's Expo knowledge is current. A strong answer explains **why** the CLI moved into the project (versioning with the SDK), names two or three of the replacements, and knows that `npx expo start` picks a development build or Expo Go based on `expo-dev-client`.
- Two projects on one laptop use different Expo SDKs; what does the local CLI change for the developer?Each project's `npx expo` resolves the `@expo/cli` installed with that project's `expo` package, so each gets a CLI matching its SDK. With the old global `expo-cli`, one binary served both, and switching projects could mean reinstalling or tolerating a mismatched CLI.
- Why is EAS CLI still installed globally when Expo CLI is not?EAS CLI drives Expo's cloud services, builds, submissions and updates, and is not tied to one project's bundler or SDK the way the dev server and prebuild are. The Expo docs therefore instruct installing it globally, while Expo CLI ships inside each project's `expo` package.
saying these in an interview costs you the question
- Install expo-cli globally before creating a project
- expo eject is still how you get native folders
- expo publish is the current way to ship an update
- npx expo start always opens Expo Go
- EAS CLI ships inside the expo package like Expo CLI