Expo Router in Practice

Layouts, tabs, dynamic routes, typed routes, modals and protected route groups in Expo Router.

Expo Router is the standard way to structure navigation in modern Expo apps. These are the patterns agents should follow.

Core concepts

  1. Root layout: app/_layout.tsx wraps the whole app. Put providers (query client, theme, auth) and the global Stack here, and import your global CSS once. — Expo Router docs
  2. Route groups: Folders in parentheses such as (tabs) or (auth) group routes without changing the URL. Use them to separate signed-in and signed-out screens. — Expo Router docs
  3. Dynamic routes: [id].tsx captures a value. Read it with useLocalSearchParams<{ id: string }>(), and validate it before use. — Expo Router docs
  4. Modals: A route can present as a modal via screen options in the Stack layout, which suits create, filter and sign-in flows. — Expo Router docs

Concept videos

YouTube channels and searches for these topics. On a large screen they open in the reading panel next to the roadmap.

Explanation

Typed routes

Turn on typed routes in app config and use Href types so navigating to a route that does not exist fails at compile time rather than at runtime.

Where state lives

Keep screens thin: they read hooks and render components. Navigation state belongs to the router, business state to your store or query cache.

What Is It?

Expo Router is a file-system router built on React Navigation that gives Expo apps URL-like paths for every screen.

Why Should I Care?

Deep links, web support and agent-friendly structure all come from one consistent routing convention.

Real World Analogy

It is a postal system where each file name is an address and layouts are the sorting offices that decide what wraps each delivery.

Visual Mental Model

text
_layout.tsx wraps -> (group)/_layout.tsx wraps -> screen.tsx

Smallest Possible Example

tsx
import { useLocalSearchParams, router } from 'expo-router';
import { Text, Pressable } from 'react-native';

export default function PostScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();
  return (
    <Pressable onPress={() => router.back()}>
      <Text>Post {id}</Text>
    </Pressable>
  );
}

Common Mistakes

❌ Trusting route params blindly.

Params are strings from a link and may be missing or malicious; validate them.

❌ Wrapping every screen in its own provider.

Providers belong in layouts so they mount once.

Build This Mini Project

Create (auth) and (tabs) groups, a dynamic /post/[id] route, and a modal route for creating a post.

Prompts for Cursor, Claude Code & Codex

Paste these into Cursor, Claude Code, Codex, or any coding agent. Replace the bracketed parts with your app details, and keep the agent in plan mode first so you review the approach before it edits files.

Refactor into groups

text
Reorganise app/ into (auth) and (tabs) route groups with the correct layouts. Keep URLs unchanged, update imports, enable typed routes, and run typecheck.

Param validation

text
Add param validation to app/post/[id].tsx using zod: show a not-found state for invalid ids and never call the API with an invalid id.

Rules, databases & blogs to use

Resources

Threads in the same domain as this chapter — go deeper on iHateReading without leaving the roadmap.

How to build an AI chat app with Vercel AI SDK and Firebase cover

How to build an AI chat app with Vercel AI SDK and Firebase

Chat UI, streaming and backend wiring for an AI feature.

Expo new version SDK 52 cover

Expo new version SDK 52

What a real Expo SDK upgrade changes for app builders.