Frequently Asked Questions About Codesistency Full-Stack Expo React Native Build Method
23 answers covering everything from basics to advanced usage.
// Basics
What is Expo and how is it different from React Native?
Expo is a platform built on top of React Native that adds file-based routing, API routes, optimised components, and production deployment tooling. It's analogous to how Next.js sits on top of React — same core, plus performance optimisations and production-ready tooling. This method always initialises with Expo rather than bare React Native.
What is a route group and why use bracketed folders?
A route group is a folder wrapped in brackets — like `(auth)/` or `(home)/` — that groups related screens without affecting the navigation URL. Each group gets its own `_layout.tsx` for shared logic such as auth guards or home guards. This lets you co-locate screens by concern and attach redirection logic per group.
What does the reset-project script do?
Running `npm run reset-project` and pressing 'No' when prompted deletes all default template screens, components, and constants so you start from a clean slate. This removes confusion from the boilerplate example files and gives you an empty `app/` folder ready for your own file-based routes.
What is the useSocialOAuth custom hook responsible for?
The `useSocialOAuth` hook encapsulates the entire Clerk SSO flow: it imports `useSSO`, manages `loadingStrategy` state for per-button spinners, guards against concurrent flows by returning early if already loading, calls `startSSOFlow({ strategy })`, runs `setActive` on success, shows an Alert on incomplete sign-in, and resets state in a finally block. It returns `{ handleSocialOAuth, loadingStrategy }`.
// How To
How do I set up automatic dark mode in a NativeWind app?
Set `darkMode: 'media'` in `tailwind.config.js`, define CSS variable colour tokens under `:root` (light) and `.dark` (dark) in `global.css` using the same variable names, then wrap the root Stack with `<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>` using `useColorScheme` from React Native. Components using classes like `bg-background` switch automatically with the device colour scheme.
How do I connect a NeonDB Postgres database with Drizzle?
Sign up at neon.tech, create a project, and copy the connection string into `.env`. Install Drizzle ORM and the Neon serverless driver, define your schema (tables, columns, relations) in TypeScript using Drizzle's syntax, then run migrations. Always read the connection string from the environment variable — never hardcode credentials.
How do I add a navigation guard so unauthenticated users are redirected?
In the `(auth)/_layout.tsx`, use Clerk's `useAuth` hook: if `!isLoaded` return null, if `isSignedIn` redirect to `/(home)`, else render `<Stack>`. In `(home)/_layout.tsx`, if `!isSignedIn` redirect to `/(auth)/sign-in`, else render `<Stack>`. This is the navigation guard pattern that protects each route group.
How do I add tab navigation with native styling?
Create a nested `_layout.tsx` using Expo Router's `<Tabs>` component, mapping each tab to a screen folder. Configure tab bar icons using vector icons from `@expo/vector-icons` such as FontAwesome or Ionicons. For the iOS liquid glass effect on tabs, apply platform-specific styles within the Tabs configuration.
How do I keep my Clerk and Neon secrets out of GitHub?
Place all secrets — the Clerk publishable key (`EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY`) and the Neon connection string — in a `.env` file at the project root, then immediately add `.env` to `.gitignore` before making any commit. Never commit credentials. This is done in step 3, before any git activity.
// Troubleshooting
Why do I get status bar overlap on my sign-in screen?
Content overlaps the device status bar because the screen isn't wrapped in `<SafeAreaView edges={['top']}>`. Always wrap screen content — especially the sign-in screen — with SafeAreaView using the top edge so text and buttons stay clear of the status bar and notch.
Why isn't Tailwind working in my screens or hooks?
This usually happens because the `content` array in `tailwind.config.js` only scans `components/`. It must scan the entire `src/` folder using `./src/**/*.{js,jsx,ts,tsx}` so NativeWind applies to screens, hooks, and all other files — not just components.
Why does my global.css import fail in _layout.tsx?
The import fails because of a wrong relative path. `global.css` lives at the project root, but `app/_layout.tsx` is inside the `app/` folder, so you must go up the correct number of levels to reach root. Adjust the relative path when importing `global.css` into the root layout.
Why do two OAuth flows fire at once when I tap fast?
Concurrent OAuth flows happen when the hook doesn't guard against them. The `useSocialOAuth` hook must return early if `loadingStrategy` is already set, and all provider buttons should be disabled while any is loading. This prevents overlapping `startSSOFlow` calls from breaking the session.
Why won't my newly installed native package work after hot reload?
JS hot reload does not pick up new native modules — you must do a full rebuild. Delete the `ios/` folder (and/or `android/`) and re-run `npx expo run:ios`. You only need to rebuild when adding new native packages; after that, JS changes hot-reload normally.
// Comparisons
How does this method compare to a generic 'follow the docs' React Native setup?
Generic setups leave you choosing tools and stitching them together ad hoc. This method is technology-opinionated: it locks in a proven free-tier stack (Expo, Clerk, Neon, Drizzle, NativeWind, Zustand), specifies exact patterns like route groups with guard layouts and custom OAuth hooks, and flags version pitfalls (NativeWind v4 not v5). You get a deterministic path from blank folder to shipped app.
How does Clerk compare to rolling your own auth?
Clerk provides ready-made hooks (`useAuth`, `useUser`, `useSSO`, `useClerk`), secure token handling, and social OAuth out of the box — with a free tier of 50,000 monthly active users. Rolling your own means building session management, token storage, and OAuth flows yourself. This method uses Clerk but builds a custom UI on top of `useSSO` for full branding control.
Should I use FlatList or Array.map to render lists?
Always use `<FlatList>` instead of `Array.map` for rendering lists on mobile. FlatList is the performant, correct React Native pattern — it virtualises rows so long lists don't degrade performance. Array.map renders everything at once, which is a common pitfall in this method.
Should I use Pressable or TouchableOpacity?
Use `<Pressable>` — it's the modern, preferred React Native component for touchable elements, replacing the older `<TouchableOpacity>`. Pressable uses `onPress`, `onLongPress`, and `onDoublePress` rather than the web's `onClick`. This method consistently favours Pressable across all screens and buttons.
// Advanced
How should I structure business logic versus UI components?
Extract reusable logic — social OAuth flows, loading state, async work — into dedicated custom hooks under a `hooks/` directory, keeping components thin. Hooks own the async work and state while components handle presentation. The `useSocialOAuth` hook is the canonical example: the sign-in screen just calls `handleSocialOAuth` and reads `loadingStrategy`.
How do I use Zustand for global state without a Provider?
Install Zustand, create stores under `src/store/` with `create()`, define state and actions, then import and use them via `useStore` in any component. Unlike Context, Zustand needs no Provider wrapper anywhere in the tree — making it ideal for app-wide state like item lists or user preferences with minimal boilerplate.
Why must screens be folders with index.tsx instead of single files?
Placing screens directly as files like `contact.tsx` means they can't have their own `_layout.tsx` for customisation. Structuring each screen as a folder with an `index.tsx` inside lets you attach layout logic, navigation configuration, and nested routes to that route. This is why the method uses `list/index.tsx` rather than `list.tsx`.
How do I add error reporting and a user feedback button?
Sign up at Sentry, install the Sentry Expo SDK, and add Sentry to `app.json` under `expo.plugins`. Use Sentry to implement a feedback button so users can report bugs or request features directly from the app. Sentry provides error monitoring alongside the feedback capture.
What's the recommended git commit cadence during the build?
Commit after every major section: stage all changes, generate a commit message, commit, and sync to GitHub — after setup, after auth, and after each screen. Create the repository as private during development and make it public only when releasing the source. This steady cadence keeps progress recoverable.