Starter Architecture

Use this starter for most solo-dev Expo apps.

app/
  _layout.tsx
  (tabs)/
    _layout.tsx
    index.tsx
    settings.tsx
  item/[id].tsx
  +not-found.tsx
src/
  api/
    client.ts
    items.ts
  hooks/
    useItems.ts
  stores/
    settingsStore.ts
  components/
    ui/
    item/
  providers/
    AppProviders.tsx
  types/
    api.ts
assets/
app.json or app.config.ts
eas.json
jest.config.js

Layer Rules

LayerOwnsKeep out
app/Routes, layouts, route-specific screen compositionAPI client internals, persistent store implementation
src/api/HTTP client, endpoint functions, DTO conversionReact components and hooks
src/hooks/Server-state hooks, route-ready data functionsRaw Axios calls in screens
src/stores/Client-only state such as settings, player state, draftsServer cache that belongs in TanStack Query
src/components/Reusable UI and feature componentsNavigation side effects that belong in routes
src/providers/Query client, safe area, theme, gesture, auth providersScreen-specific data fetching

Minimal Root Layout

import { Stack } from 'expo-router';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export default function RootLayout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <QueryClientProvider client={queryClient}>
        <Stack />
      </QueryClientProvider>
    </GestureHandlerRootView>
  );
}

Start Smaller Than You Think

Include in v1:

  • Expo Router.
  • TypeScript.
  • One API client module.
  • One server-state pattern.
  • One client-state store only if needed.
  • Jest and one route/screen test.
  • EAS profiles for development, preview, and production.

Defer until there is pressure:

  • Custom native modules.
  • Multiple app variants.
  • Background jobs.
  • Deep local-first sync.
  • Custom config plugins.
  • Complex navigation state outside Expo Router.

Gotcha: Do not put tests inside app/. Expo Router treats files under app/ as route inputs. Keep tests in __tests__/, colocated outside app/, or under src/.