MVP: ship it.
- Users
- 0 to a few hundred testers
- Team
- You, plus an agent
You are here if
- You are still on TestFlight or internal testing
- No native module you cannot get from the Expo SDK
- You can ship a new build whenever you like
- The backend is a hosted service, not code you maintain
The fastest mobile MVP is the one with no native code. Expo’s managed workflow, Expo Router and a hosted backend such as Supabase let the agent work entirely in TypeScript, preview on a phone in seconds, and push JavaScript updates over the air. Every native dependency you avoid is a build step, a review cycle and a class of bug the agent cannot see.
What changes when you leave this tier: real users on old versions. That means a versioned API, a device test flow before each release, and an EAS build pipeline the agent can trigger but not skip.
Consumer · content & social
Expo + Expo Router + Supabase
A feed-shaped app with auth, storage and realtime from a hosted backend, and not a line of native code.
The stack
- Framework
- Expo (managed workflow) + Expo Router
- Data
- Supabase (Postgres, Storage, Realtime)
- Auth
- Supabase Auth
- Hosting
- EAS Update for over-the-air JavaScript, TestFlight and internal testing
- Also
- NativeWind for stylingFlashList for feedsexpo-image for mediaExpo Notifications
Why agents do well here
5/5- Expo Router makes screens files and params types, so the agent navigates the app the way it navigates a web app.
- Supabase gives the agent one client for auth, data, files and realtime, all typed from the database schema.
- Over-the-air updates mean an agent's fix ships in minutes, keeping the feedback loop tight enough to be useful.
Avoid at this tier
- Ejecting or adding a custom native module for anything the Expo SDK already covers.
- A bespoke backend; you will spend the MVP on plumbing instead of the feed.
- Redux or a large state library; TanStack Query plus a small store is enough.
Consumer apps are lists, media and notifications. Pick the list, image and push libraries first, because retrofitting them is exactly the kind of cross-cutting change an agent does badly.
app/ (tabs)/feed.tsx, (tabs)/profile.tsx, post/[id].tsx, _layout.tsx
src/features/ feed/, auth/, profile/ {hooks, components, queries}
src/lib/ supabase.ts, query-client.ts
supabase/ migrations/, seed.sql
First five decisions: managed workflow with no native code, Expo Router with typed routes, FlashList and expo-image from the start, Supabase RLS for authorisation, and EAS Update wired before the first tester.
Companion · mobile face of a SaaS
Expo in the web app's monorepo
Add an Expo app next to the web app, share the schema and API client, and let one change land in both.
The stack
- Framework
- Expo + Expo Router inside the existing monorepo
- Data
- Whatever the web app already uses, through its API
- Auth
- The web app's provider (Supabase Auth, Clerk, Auth.js) via its native SDK
- Hosting
- EAS Update; store builds only when native dependencies change
- Also
- NativeWind sharing the web app's Tailwind tokensShared packages for types, validation and the API clientTanStack Query on both surfaces
Why agents do well here
5/5- Shared packages mean the agent changes a type once and both apps fail to compile until they agree.
- The agent already knows the domain from the web app, so mobile screens are mostly translation, which it does reliably.
- One repository, one package manager and one test command keep the agent's context small.
Avoid at this tier
- A second backend for mobile; consume the web app's API.
- Copying types across instead of sharing a package.
- Building every web screen for mobile; pick the three flows people need on a phone.
A companion app should feel like a second window onto the same product.
Put it in apps/mobile/, move shared types and the API client into
packages, and keep the mobile screens to the flows that matter on a phone.
apps/web/ the existing product
apps/mobile/ app/ (Expo Router), src/features/
packages/schema/ zod schemas and types both apps import
packages/api-client/ typed client, generated or hand-written once
First five decisions: monorepo from day one, shared schema package, the web app’s auth provider with its native SDK, three flows not thirty, and EAS Update so the agent’s fixes skip review.
Tool · offline-first utility
Expo + SQLite, local-first
One workflow, data on the device, no backend to run, and a sync layer only if you ever need one.
The stack
- Framework
- Expo (managed workflow) + Expo Router
- Data
- expo-sqlite with Drizzle ORM
- Hosting
- EAS Update; a single store listing
- Also
- NativeWindMMKV or AsyncStorage for settingsexpo-file-system for exports
Why agents do well here
5/5- No backend means the entire app is one TypeScript project the agent can read and run end to end.
- Drizzle over SQLite gives the agent a typed schema on the device, so local data has the same rigour as a server database.
- A tool has one job, so the screens, the schema and the tests all fit in context together.
Avoid at this tier
- A cloud backend before someone asks to see their data on a second device.
- Native modules for storage; the Expo SDK already covers it.
- Accounts; a tool that works offline should not need a login.
Most utilities never need a server. Keep the data on the phone in SQLite with a typed schema, and export to a file when someone wants their data elsewhere. If sync becomes a real request, add it as a separate feature rather than rebuilding the app around it.
app/ index.tsx, item/[id].tsx, settings.tsx, _layout.tsx
src/db/ schema.ts, migrations/, client.ts (expo-sqlite + Drizzle)
src/features/ <workflow>/ {screens, hooks, tests}
First five decisions: local SQLite as the only store, Drizzle migrations bundled with the app, no accounts, file export as the sync story, and EAS Update for fixes.