ReadyNative

Stack comparison

One option per category - what each one costs you (Expo Go, keys, native code) and what it requires

Every option of every category side by side. bun run setup asks one question per category; every answer is a module under modules/<category>/<option>/. Non-interactive: bun run setup --preset default --ui tamagui --auth supabase --yes. This page is generated from the same module.json files setup reads, so it can't drift from what ships. For how to choose, read Pick your stack first.

Presets

Categoryminimaldefaultsaas
uinativewind4nativewind4nativewind4
datanonereact-queryreact-query
statenonezustandzustand
storagekv-storekv-storekv-store
formsnonereact-hook-formreact-hook-form
i18nnonei18nexti18next
authnonenonesupabase
paymentsnonenonerevenuecat
analyticsnonenoneposthog
crashnonenonesentry
pushnonenoneexpo-notifications
backendnonenoneapi-routes
onboardingoffonon
locationnoneexpo-locationexpo-location
widgetsnonenoneexpo-widgets
consentnonenoneconsent
testingnonejestjest

The committed tree equals setup --preset default; saas is default plus every service category turned on.

UI (ui)

OptionLabelExpo GoHint
nativewind4NativeWind 4 (default)yesStable · Tailwind 3 classes + RNR components behind @/ui · Expo Go OK
nativewind5NativeWind 5yesRC · Tailwind 4 classes behind @/ui · Expo Go OK
tamaguiTamaguiyesTamagui 2 (v5 config, optimising compiler) behind @/ui · Expo Go OK
unistylesUnistyles 3no - dev build requiredC++ StyleSheet with themes/breakpoints behind @/ui · dev build required (no Expo Go)
stylesheetStyleSheet (plain RN)yesno style engine, tokens + StyleSheet.create · Expo Go OK

Data (data)

OptionLabelExpo GoHint
react-queryTanStack Query (default) (most people pick this)yesserver state + cache · Expo Go OK
apolloApollo ClientyesGraphQL client + normalized cache · Expo Go OK
swrSWRyesstale-while-revalidate hooks · Expo Go OK
noneNo data layeryesplain fetch; add TanStack Query/Apollo/SWR later

State (state)

OptionLabelExpo GoHint
zustandZustand (default) (most people pick this)yestiny stores, persisted on the storage adapter · Expo Go OK
jotaiJotaiyesatomic state, persisted on the storage adapter · Expo Go OK
noneNo state libraryyesbuilt-in useSyncExternalStore stores only
  • zustand: requires storage ∈ kv-store | mmkv | async-storage
  • jotai: requires storage ∈ kv-store | mmkv | async-storage

Storage (storage)

OptionLabelExpo GoHint
kv-storeexpo-sqlite/kv-store (default) (most people pick this)yessync + async key/value on SQLite · Expo Go OK
mmkvMMKVno - dev build requiredfastest sync key/value (Nitro) · dev build required (no Expo Go)
async-storageAsyncStorageyesasync-only key/value, the community standard · Expo Go OK

Forms (forms)

OptionLabelExpo GoHint
react-hook-formReact Hook Form (default) (most people pick this)yesForm + Field on @/ui Input, zod resolver · Expo Go OK
noneNo forms libraryyescontrolled @/ui Inputs with useState

i18n (i18n)

OptionLabelExpo GoHint
i18nexti18next (default) (most people pick this)yesreact-i18next + expo-localization, 6 languages bundled incl. Arabic (RTL) · Expo Go OK
linguiLinguiyes@lingui/core + @lingui/react runtime API, 6 languages bundled incl. Arabic (RTL) · Expo Go OK
noneNo i18nyesi18n.t/useT return the English key
  • i18next: requires storage ∈ kv-store | mmkv | async-storage
  • lingui: requires storage ∈ kv-store | mmkv | async-storage

Auth (auth)

OptionLabelExpo GoHint
supabaseSupabase Auth (default) (most people pick this)yesemail+password, Apple (native), Google (OAuth) · session on the storage adapter · Expo Go OK
clerkClerkyesemail+code verification, Apple (native), Google (SSO) · @clerk/expo · Expo Go OK for JS flows
better-authBetter Authyesself-hosted on the API routes · email/password + Apple/Google · Expo Go OK
noneNo authyesauth.useSession() shim returns signed-out, signOut resolves
  • supabase: requires storage ∈ kv-store | mmkv | async-storage; needs EXPO_PUBLIC_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_ANON_KEY
  • clerk: requires storage ∈ kv-store | mmkv | async-storage; needs EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
  • better-auth: requires backend ∈ api-routes; needs BETTER_AUTH_SECRET, BETTER_AUTH_URL

Payments (payments)

OptionLabelExpo GoHint
revenuecatRevenueCat (default) (most people pick this)no - dev build requiredin-app subscriptions + paywall · dev build required (no Expo Go)
adaptyAdaptyno - dev build requiredin-app subscriptions + Paywall Builder · dev build required (no Expo Go)
stripeStripe Checkoutyesweb checkout via API routes (no native SDK) · Expo Go OK
noneNo paymentsyespayments.useEntitlements() shim returns none
  • revenuecat: needs EXPO_PUBLIC_REVENUECAT_IOS_KEY, EXPO_PUBLIC_REVENUECAT_ANDROID_KEY
  • adapty: needs EXPO_PUBLIC_ADAPTY_PUBLIC_KEY
  • stripe: requires backend ∈ api-routes; needs EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_ID

Analytics (analytics)

OptionLabelExpo GoHint
posthogPostHog (default) (most people pick this)yesproduct analytics + feature flags (analytics.isFeatureEnabled / useFeatureFlag) · Expo Go OK
amplitudeAmplitudeyesproduct analytics · Expo Go OK (JS SDK, storage adapter)
noneNo analyticsyesanalytics.track/identify/screen are no-ops, feature flags read undefined
  • posthog: requires storage ∈ kv-store | mmkv | async-storage; needs EXPO_PUBLIC_POSTHOG_KEY
  • amplitude: requires storage ∈ kv-store | mmkv | async-storage; needs EXPO_PUBLIC_AMPLITUDE_KEY

Crash reporting (crash)

OptionLabelExpo GoHint
sentrySentry (default) (most people pick this)yesJS + native crash reporting · Expo Go OK (JS errors only)
noneNo crash reportingyescrash.capture is a no-op
  • sentry: needs EXPO_PUBLIC_SENTRY_DSN

Push notifications (push)

OptionLabelExpo GoHint
expo-notificationsExpo Notifications (default) (most people pick this)no - dev build requiredExpo push service + local notifications · dev build required for remote push (Expo Go: local only)
noneNo push notificationsyesnothing registered

Backend (backend)

OptionLabelExpo GoHint
api-routesAPI routes (default) (most people pick this)yesExpo Router +api.ts routes · src/server helpers · EAS Hosting · Expo Go OK
noneNo API routesyesno src/app/api

Onboarding (onboarding)

OptionLabelExpo GoHint
onOnboarding flow (default)yes3-slide intro at /onboarding, redirect until completed
offNo onboardingyesapp opens straight into the tabs

Location (location)

OptionLabelExpo GoHint
expo-locationExpo Location (default) (most people pick this)yesforeground position + reverse geocoding, permission states handled · Expo Go OK
noneNo locationyesno permission prompt, no expo-location

Home-screen widgets (widgets)

OptionLabelExpo GoHint
expo-widgetsExpo Widgets (default) (most people pick this)no - dev build requirediOS home-screen widget + Live Activity (Lock Screen, Dynamic Island) in SwiftUI (@expo/ui), fed from the app · dev build required (no Expo Go)
noneNo widgetsyesno app extension, widgets.update() is a no-op
OptionLabelExpo GoHint
consentConsent sheet (GDPR / CCPA) (default) (most people pick this)yesasks before analytics + crash start (EU/EEA, UK, Switzerland, Canada, Brazil or everywhere); Settings toggles · Expo Go OK
noneNo consent sheetyesconsent.get() reads all-true; analytics and crash SDKs start as before

Testing (testing)

OptionLabelExpo GoHint
jestJest + Testing Library (default) (most people pick this)yesjest-expo preset, RNTL, tests for stores/theme/ui
noneNo test runneryesno jest; module tests are removed

On this page

Get ReadyNative