mrkeyoor.com_
Wed 05 Aug 05:05 UTC
npmMobileupdated 05 Aug 2026

expo

Expo is an open-source platform on top of React Native for building Android, iOS, and web apps from one JavaScript or TypeScript codebase. The expo package is the SDK and runtime; the same monorepo ships the CLI, Expo Router for file-based navigation, the Modules API for native code, and the Expo Go sandbox app. It pairs with EAS, Expo's hosted build, submit, and update service, which is where most of the ship-to-store convenience actually lives.

Verdict

The default way to build React Native apps and the fastest zero-to-device experience in mobile. Go in knowing the comfortable shipping path routes through EAS and that SDK upgrades are recurring scheduled work, not a one-time cost.

API stability4/5Versioned SDK releases with per-SDK dist-tags (sdk-52 through sdk-56 are all published, with 57 as latest) and documented upgrade paths; APIs deprecate across SDK cycles rather than breaking silently, but upgrades are still regular work.
Docs5/5docs.expo.dev is versioned per SDK with guides, per-module API reference, and upgrade notes; the README points there and to a maintained FAQ.
Maintenance5/5Backed by the Expo company; the monorepo shows pushes within hours of this review (2026-08-05) and parallel maintenance of multiple SDK lines plus canary releases.
Ecosystem4/5Dozens of first-party modules, Expo Router, and EAS cover most app needs, and 51k stars reflect wide adoption; a minority of community React Native libraries still assume a bare workflow and need config plugins or a dev build.

Use it if

  • You want a new React Native app running on a real device in minutes, with routing, TypeScript, and a large set of prebuilt native modules preconfigured
  • Your team is mostly web developers; the dev server plus Expo Go gives fast iteration without touching Xcode or Android Studio for JS-only work
  • You want cloud builds and over-the-air JS updates through EAS instead of maintaining your own CI with macOS runners
  • You need one codebase targeting Android, iOS, and web
Skip it if

Setup reality

npx create-expo-app to a running app on your phone via Expo Go is the easiest start in mobile, full stop. The honest parts come later: adding any library with custom native code forces a development build (npx expo run:ios needs a Mac with Xcode, or you use EAS Build in the cloud with an Expo account), SDK upgrades arrive several times a year and each one is a real chore across native config and dependencies, and version mismatches are common enough that npx expo install exists specifically to pin packages to versions your SDK supports.

Patterns

Create and run a new appcreate-app

npx create-expo-app@latest my-app
cd my-app
npx expo start

Scan the QR code with Expo Go on your phone; the template already includes Expo Router and TypeScript.

Install an SDK-compatible packageinstall-compatible-package

npx expo install expo-camera expo-location

Always use expo install instead of npm install for Expo and React Native packages; it pins versions known to work with your SDK.

Add a screen with Expo Routerfile-based-routing

// app/index.tsx
import { Link } from 'expo-router';
import { Text, View } from 'react-native';

export default function Home() {
  return (
    <View>
      <Text>Home</Text>
      <Link href="/about">About</Link>
    </View>
  );
}

// app/about.tsx
export default function About() {
  return <Text>About</Text>;
}

The file path under app/ is the route; no navigator registration code needed.

Run a development build locallydevelopment-build

npx expo run:ios      # needs a Mac with Xcode
npx expo run:android  # needs Android Studio / SDK

Required as soon as you add a library with custom native code; Expo Go only contains the modules that ship with the SDK.

Use environment variablesenvironment-variables

# .env
EXPO_PUBLIC_API_URL=https://api.example.com

// anywhere in app code
const url = process.env.EXPO_PUBLIC_API_URL;

EXPO_PUBLIC_ values are inlined into the client bundle at build time; never put secrets in them.

Configure app identity in app.jsonapp-config

{
  "expo": {
    "name": "My App",
    "slug": "my-app",
    "ios": { "bundleIdentifier": "com.example.myapp" },
    "android": { "package": "com.example.myapp" }
  }
}

Changes to native config only take effect in a new build, not through a JS reload or an OTA update.

Ask for camera permission and show a previewcamera-permission

import { CameraView, useCameraPermissions } from 'expo-camera';
import { Button, Text, View } from 'react-native';

export default function Scanner() {
  const [permission, requestPermission] = useCameraPermissions();
  if (!permission) return <View />;
  if (!permission.granted) {
    return <Button title="Allow camera" onPress={requestPermission} />;
  }
  return <CameraView style={{ flex: 1 }} />;
}

iOS also requires a usage description string in app.json (via the expo-camera config plugin) or the app gets rejected.

Load a custom fontload-fonts

import { useFonts } from 'expo-font';

export default function Root() {
  const [loaded] = useFonts({
    Inter: require('./assets/fonts/Inter-Regular.ttf'),
  });
  if (!loaded) return null;
  return <App />;
}

Fonts load async at runtime with useFonts; for zero-flash embedding at build time use the expo-font config plugin instead.

Build in the cloud with EAScloud-build

npm install -g eas-cli
eas login
eas build --platform ios

Needs an Expo account and your app store credentials; this is the path that avoids owning a Mac for iOS builds.

Upgrade to a new SDK versionupgrade-sdk

npx expo install expo@latest
npx expo install --fix

expo install --fix realigns every dependency to the new SDK; upgrade one SDK version at a time and read that release's changelog.

Alternatives

PackageRegistryPick it when
react-nativenpmBare React Native when you need full control of the native iOS and Android projects
@capacitor/corenpmWrap an existing web app in a native shell instead of rendering native views
nativescriptnpmNative UI from JavaScript without React in the stack