Expo
Managed React Native tooling: config plugins, EAS builds and over-the-air updates.
The rule
This is the whole text, exactly as your agent receives it. Nothing is held back for the paid tier.
Installing packages
npx expo install <package>for anything Expo-related — it resolves the version matching the installed SDK. Plainnpm installproduces version mismatches whose error messages point somewhere else entirely.- After adding a package with native code, the dev client must be rebuilt.
Native configuration
- All native config goes in
app.json— permissions, bundle identifiers, icons, plugins. Never editios/orandroid/directly:expo prebuildregenerates them and discards the change. - A library needing native setup ships a config plugin. Add it to
pluginsrather than patching the generated project.
Environment variables
- Only
EXPO_PUBLIC_*variables reach the app, and they are embedded in the bundle. Treat every one as public. - Secrets go in EAS secrets or on a server. Never in
EXPO_PUBLIC_*.
Updates
eas updateships JavaScript only.- Any change touching native code — a new native dependency, a permission, an icon — requires a new build. Shipping an OTA update that expects a missing native module crashes the app on launch for everyone who receives it.
- Update channels must match build channels.
Builds
- Keep
development,previewandproductionprofiles separate ineas.json, each with its own environment variables and credentials. - Increment
ios.buildNumberandandroid.versionCodefor every store upload.
Never
- Never commit a keystore, certificate, or
.env. - Never point a non-production profile at production credentials.
- Never hand-edit generated native folders.
6 formats, one per tool
Each tab is the file that tool actually reads, at the path it actually looks in. Knowing where each one looks is most of the work of supporting it.
---
description: Expo conventions
globs: ["**/*.tsx", "**/*.ts", "app.json", "eas.json"]
alwaysApply: false
---
# Expo
## Installing packages
- `npx expo install <package>` for anything Expo-related — it resolves the
version matching the installed SDK. Plain `npm install` produces version
mismatches whose error messages point somewhere else entirely.
- After adding a package with native code, the dev client must be rebuilt.
## Native configuration
- All native config goes in `app.json` — permissions, bundle identifiers, icons,
plugins. Never edit `ios/` or `android/` directly: `expo prebuild` regenerates
them and discards the change.
- A library needing native setup ships a config plugin. Add it to `plugins`
rather than patching the generated project.
## Environment variables
- Only `EXPO_PUBLIC_*` variables reach the app, and they are **embedded in the
bundle**. Treat every one as public.
- Secrets go in EAS secrets or on a server. Never in `EXPO_PUBLIC_*`.
## Updates
- `eas update` ships JavaScript only.
- Any change touching native code — a new native dependency, a permission, an
icon — requires a new build. Shipping an OTA update that expects a missing
native module crashes the app on launch for everyone who receives it.
- Update channels must match build channels.
## Builds
- Keep `development`, `preview` and `production` profiles separate in
`eas.json`, each with its own environment variables and credentials.
- Increment `ios.buildNumber` and `android.versionCode` for every store upload.
## Never
- Never commit a keystore, certificate, or `.env`.
- Never point a non-production profile at production credentials.
- Never hand-edit generated native folders.
Hand-written by the module author, frontmatter and all. It is the source the four derived formats are rendered from, so a correction lands here first.
What else this module writes
The rule is one file of several. Selecting Expo contributes all of this too — merged with every other module you pick, with conflicts resolved rather than duplicated.
EXPO_PUBLIC_API_URLrequiredBase URL the app calls. One per environment.EXPO_PUBLIC_ENVoptionalEnvironment label used for feature gating and diagnostics.EXPO_TOKENoptionalEAS access token. CI only — never in a local `.env` that could be committed.Advisory history
Every time this rule turned out to be wrong, and what we did about it.
This rule has been accurate since it was published. That is a fact about the rule, not a promise about the future — which is the whole reason this section exists.
Pro tells you the day a correction lands that affects a repo you actually have.
See what Pro adds →Rules people add alongside this one
The wizard picks the rest of the stack with you, writes all 6 formats, and leaves a manifest so check can tell you when any of it drifts.