Managed Workflow (CNG)
The team default is Expo’s managed workflow with Continuous Native
Generation (CNG): the ios/ and android/ folders are never committed.
They’re generated on demand — locally with npx expo prebuild, or
transparently by EAS Build in the cloud — from app.config.ts and the
packages you install.
Why not “either is fine”? Committed native folders turn every native
config change into an unreadable diff, create a second source of truth
(hand-edited native files vs. app.config.ts) that silently drifts, and make
onboarding depend on which workflow a given clone happens to be in. CNG keeps
exactly one source of truth.
Day to day
- Bundle IDs, permissions, deep-link schemes, and other native identifiers are
changed in
app.config.ts— see Environment & Configuration → Build-Time Config — never by hand in Xcode or Android Studio. - Need to inspect or run a native project locally? Run
npx expo prebuild --cleanto (re)generateios/andandroid/. Treat the result as disposable build output: never commit it, and delete/regenerate it if it ever looks like it’s drifted from your config. - Store and internal builds never require anyone to run
prebuildby hand — EAS Build runs it in the cloud as part of every build. See Build & Distribution → Concepts.
When a config plugin doesn’t cover what you need
Most native capabilities ship as an official or community Expo config
plugin: add it to app.config.ts’s plugins array and prebuild wires it
into the generated native project for you. Before writing anything custom,
search npm/GitHub for one (<sdk name> expo plugin, expo-config-plugin-*).
If none exists — some vendor SDKs (KYC/identity verification, payments, etc.)
only ship native install instructions, no Expo integration — the answer is a
local config plugin, not ejecting to bare and not committing
ios//android/. See Project Architecture → Native SDKs Without an Expo
Plugin.
Joining a project that already has ios//android/ committed? That’s an
inherited bare setup, not something to “fix” as a side effect of unrelated
work. Migrating an existing project to managed is its own planned change —
raise it separately instead of doing it inline.