> expo-router

Build native mobile apps with file-based routing using Expo Router — React Native navigation that works like Next.js. Use when someone asks to "add navigation to React Native", "Expo Router", "file-based routing for mobile", "deep linking in React Native", "mobile app navigation", or "React Native routing like Next.js". Covers file-based routes, layouts, deep linking, tabs, stacks, and universal links.

fetch
$curl "https://skillshub.wtf/TerminalSkills/skills/expo-router?format=md"
SKILL.mdexpo-router

Expo Router

Overview

Expo Router brings file-based routing to React Native — the same pattern as Next.js but for mobile apps. Drop a file in app/, get a screen. Folder structure defines navigation hierarchy: stacks, tabs, drawers, and modals. Deep linking works automatically — every route has a URL. Build iOS, Android, and web from one codebase with the same routing system.

When to Use

  • Building a React Native / Expo app that needs navigation
  • Want file-based routing instead of manual React Navigation config
  • Need deep linking and universal links without extra setup
  • Building a universal app (iOS + Android + Web)
  • Migrating from React Navigation to a simpler routing model

Instructions

Setup

npx create-expo-app@latest my-app --template tabs
cd my-app
npx expo start

File-Based Routes

app/
├── _layout.tsx          # Root layout (wraps all screens)
├── index.tsx            # / (home screen)
├── about.tsx            # /about
├── (tabs)/              # Tab navigation group
│   ├── _layout.tsx      # Tab bar configuration
│   ├── index.tsx        # First tab (home)
│   ├── explore.tsx      # Second tab
│   └── profile.tsx      # Third tab
├── settings/
│   ├── _layout.tsx      # Stack layout for settings
│   ├── index.tsx        # /settings
│   ├── account.tsx      # /settings/account
│   └── notifications.tsx # /settings/notifications
├── [id].tsx             # /123 (dynamic route)
├── post/
│   └── [slug].tsx       # /post/my-first-post
└── +not-found.tsx       # 404 screen

Root Layout

// app/_layout.tsx — Root layout with stack navigation
import { Stack } from "expo-router";

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="settings" options={{ title: "Settings" }} />
      <Stack.Screen
        name="modal"
        options={{ presentation: "modal", title: "Info" }}
      />
    </Stack>
  );
}

Tab Navigation

// app/(tabs)/_layout.tsx — Bottom tab bar
import { Tabs } from "expo-router";
import { Ionicons } from "@expo/vector-icons";

export default function TabLayout() {
  return (
    <Tabs screenOptions={{ tabBarActiveTintColor: "#007AFF" }}>
      <Tabs.Screen
        name="index"
        options={{
          title: "Home",
          tabBarIcon: ({ color }) => <Ionicons name="home" size={24} color={color} />,
        }}
      />
      <Tabs.Screen
        name="explore"
        options={{
          title: "Explore",
          tabBarIcon: ({ color }) => <Ionicons name="compass" size={24} color={color} />,
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: "Profile",
          tabBarIcon: ({ color }) => <Ionicons name="person" size={24} color={color} />,
        }}
      />
    </Tabs>
  );
}

Navigation and Dynamic Routes

// app/(tabs)/index.tsx — Home screen with navigation
import { Link, router } from "expo-router";
import { View, Text, Pressable, FlatList } from "react-native";

export default function HomeScreen() {
  const posts = usePosts();

  return (
    <View>
      {/* Declarative navigation */}
      <Link href="/about">About</Link>
      <Link href="/settings">Settings</Link>
      <Link href="/post/hello-world">My Post</Link>

      {/* Programmatic navigation */}
      <Pressable onPress={() => router.push("/settings/account")}>
        <Text>Go to Account</Text>
      </Pressable>

      {/* Dynamic routes */}
      <FlatList
        data={posts}
        renderItem={({ item }) => (
          <Link href={`/post/${item.slug}`}>
            <Text>{item.title}</Text>
          </Link>
        )}
      />
    </View>
  );
}
// app/post/[slug].tsx — Dynamic route screen
import { useLocalSearchParams } from "expo-router";

export default function PostScreen() {
  const { slug } = useLocalSearchParams<{ slug: string }>();
  const post = usePost(slug);

  return (
    <View>
      <Text style={{ fontSize: 24 }}>{post?.title}</Text>
      <Text>{post?.content}</Text>
    </View>
  );
}

Deep Linking (Automatic)

// app.json — Deep linking just works
{
  "expo": {
    "scheme": "myapp",
    "web": { "bundler": "metro" }
  }
}

Every route automatically gets a URL:

  • myapp:// → Home screen
  • myapp://post/hello-world → Post screen
  • https://myapp.com/post/hello-world → Same screen (universal links)

Examples

Example 1: Build a social media app navigation

User prompt: "Set up navigation for a social app — tabs for feed/search/profile, stack for post details, and modal for creating posts."

The agent will create tab layout, nested stack routes, and a modal route with proper animations and deep linking.

Example 2: Add authentication flow

User prompt: "Add login/signup screens that show before the main app tabs."

The agent will create a route group for auth screens, use layout redirection based on auth state, and protect tab routes.

Guidelines

  • File = routeapp/about.tsx = /about screen
  • _layout.tsx for navigation containers — Stack, Tabs, Drawer
  • (group) for route groups — organize without affecting URL
  • [param] for dynamic routes — access via useLocalSearchParams
  • Deep linking is automatic — every route has a URL
  • Link for declarative, router for programmatic — navigation
  • +not-found.tsx for 404 — catches unmatched routes
  • Typed routeshref autocompletes with TypeScript
  • Web support — same routes work on web with expo-router
  • presentation: "modal" in options — for modal screens

> related_skills --same-repo

> zustand

You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.

> zoho

Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.

> zod

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

> zipkin

Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.

┌ stats

installs/wk0
░░░░░░░░░░
github stars17
███░░░░░░░
first seenMar 17, 2026
└────────────

┌ repo

TerminalSkills/skills
by TerminalSkills
└────────────

┌ tags

└────────────