Expo project tour

app/, components/, hooks/.

7 mineasy

Tour the Expo project. By the end you'll know which folder holds what and how file-based routing works in Expo Router.

The tree

apps/mobile/
apps/mobile/
ā”œā”€ā”€ app/ file-based routes (= URLs / screens)
│ ā”œā”€ā”€ _layout.tsx root layout, mounts providers
│ ā”œā”€ā”€ index.tsx the home screen
│ ā”œā”€ā”€ (auth)/ grouped routes (parens = no URL segment)
│ │ ā”œā”€ā”€ _layout.tsx
│ │ ā”œā”€ā”€ login.tsx
│ │ └── register.tsx
│ └── (tabs)/ tabbed navigation
│ ā”œā”€ā”€ _layout.tsx
│ ā”œā”€ā”€ index.tsx first tab
│ └── settings.tsx
ā”œā”€ā”€ components/ reusable UI (Button, Card, …)
ā”œā”€ā”€ hooks/ useAuth, useUsers, …
ā”œā”€ā”€ lib/ api client, secure-storage, utils
ā”œā”€ā”€ assets/ images, fonts, icons
ā”œā”€ā”€ app.json Expo config (name, icons, splash, deep linking)
ā”œā”€ā”€ eas.json build profiles (preview, production)
ā”œā”€ā”€ tsconfig.json
└── package.json

File-based routing

Same pattern as Next.js App Router. The file becomes the URL.

app/index.tsx → /
app/about.tsx → /about
app/(auth)/login.tsx → /login ← (auth) doesn't appear in URL
app/users/[id].tsx → /users/123
app/_layout.tsx → wraps every child screen

Grouped routes — the (parens) trick

Folders in parens are route groups. They organise files without affecting the URL. Use them to share a layout across related screens:

app/
ā”œā”€ā”€ (auth)/_layout.tsx auth-screen layout (centered card, no tabs)
│ ā”œā”€ā”€ login.tsx
│ └── register.tsx
└── (tabs)/_layout.tsx main app layout (with bottom tab bar)
ā”œā”€ā”€ index.tsx
└── settings.tsx

Same URLs as before — /login, /register,/, /settings. Different shells.

The root layout

app/_layout.tsx
import { Stack } from 'expo-router'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { AuthProvider } from '@/hooks/use-auth'
const queryClient = new QueryClient()
export default function RootLayout() {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<Stack screenOptions={{ headerShown: false }} />
</AuthProvider>
</QueryClientProvider>
)
}

Mounts React Query + AuthProvider once for the whole app. Every screen below it can call useQuery and useAuth().

The screen that renders is decided by URL. Push navigation with router.push('/users/123'); the file at app/users/[id].tsx renders with useLocalSearchParams() returning { id: '123' }.

Quick check

You have a checkout flow with 3 screens: cart, shipping, payment. You want all three to share a step-progress header but DIFFERENT URLs (/cart, /shipping, /payment). What's the right shape?

Try it

Open apps/mobile/app/_layout.tsx in your scaffolded project. Read it. Then in notes.md:

  1. List what providers it wraps the app in
  2. List what screens are accessible (look at the file tree under app/)
  3. Find one routegroup (folder in parens). Write its purpose in one sentence.

What's next

Last lesson of this chapter — actually run it. Simulator vs Expo Go vs dev build, and which to use when.

Spot a typo? Have an idea?

Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled — suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.

Suggest an improvement on GitHub