React Native Navigation Guide: Expo Router, Deep Links, Tabs, and Nested Stacks
React NativeExpo RouterNavigationDeep LinkingApp Architecture

React Native Navigation Guide: Expo Router, Deep Links, Tabs, and Nested Stacks

NNative Dev Hub Editorial Team
2026-11-02
7 min read

A practical Expo Router checklist for React Native stacks, tabs, nested routes, modals, deep links, parameters, and navigation testing.

Expo Router gives React Native apps a file-based way to organize stacks, tabs, modals, dynamic screens, and deep links. This guide provides a reusable navigation checklist, with practical examples for choosing a route structure, passing parameters, handling loading states, testing links, and maintaining navigation as the app grows.

Overview

React Native navigation is easier to maintain when the route tree reflects the product structure. With Expo Router, files and folders inside the app directory define routes, while layout files define shared navigation such as stacks and tabs. That convention reduces the amount of navigator configuration you write, but it does not remove the need to design boundaries carefully.

A small app may need only a root stack and a few screens. A larger app commonly needs a public area, an authenticated area, tabs for primary destinations, nested stacks for detail flows, modal screens, and routes that can be opened from notifications or web links. Decide those boundaries before adding screens. A useful starting point is to classify every destination as one of four types:

  • Primary destination: a screen users visit repeatedly, such as Home, Search, or Account.
  • Drill-down screen: a detail or edit screen reached from another route.
  • Transient screen: a modal, picker, confirmation, or focused task.
  • External-entry screen: a route that may open from a deep link, notification, email, or widget.

For authentication and protected route patterns, see the React Native authentication with Expo Router guide. For a broader file-based routing reference, the Expo Router guide covers related architecture decisions.

Checklist by scenario

1. Basic stack navigation

Use a stack when users move from a list to a detail screen or through a sequential task. A minimal structure can look like this:

app/
  _layout.tsx
  index.tsx
  settings.tsx
  products/
    index.tsx
    [id].tsx

The root layout can define the default stack:

import { Stack } from 'expo-router';

export default function RootLayout() {
  return <Stack />;
}

Before adding a route, check that its URL-like path is understandable, its screen has a clear back behavior, and its title can be set independently of the component implementation. Prefer route names that describe destinations rather than actions when the screen may be opened from multiple places.

2. Tabs with nested stacks

Tabs should represent stable top-level areas, not every possible screen. Put a stack inside each tab when that area has its own list-to-detail flow:

app/
  (tabs)/
    _layout.tsx
    home/
      _layout.tsx
      index.tsx
      details.tsx
    account/
      _layout.tsx
      index.tsx
      preferences.tsx

The tab layout owns the tab bar, while each child layout owns the stack for that tab. This keeps detail screens inside the correct tab history and prevents the tab navigator from becoming a list of unrelated screens. In the tab layout, hide routes that should not appear as tab buttons and configure labels and icons in one place.

3. Dynamic routes and shared parameters

Use bracket notation for a route whose path contains an identifier, such as products/[id].tsx. Read the parameter with the router hooks appropriate to your Expo Router version, then treat it as untrusted input: validate its shape, handle a missing record, and show a useful loading or error state.

Pass stable identifiers rather than entire objects. A route such as /products/42 can be restored, shared, and opened from a deep link. Passing a large serialized object can create stale data and makes links difficult to reproduce. If a detail screen needs fresh data, load it using the identifier and provide a placeholder while the request is pending.

4. Modal screens and focused tasks

Use a modal presentation for short tasks that should return users to the current context, such as selecting a filter or confirming an action. Define the modal in a stack layout and make dismissal predictable. Confirm that Android back behavior, the close button, and a completed action all lead to the intended previous screen.

Do not use a modal merely to avoid deciding where a screen belongs. If a screen has its own navigation flow, permissions, or several steps, a nested stack may be clearer than a single modal route.

5. Deep links and external entry points

List every external-entry route and test it from a cold launch, a warm app, and an already-open screen. A deep link should resolve to a meaningful state even when the user has not visited the preceding screen in the normal flow.

For each link, verify the scheme or domain configuration, path parameters, authentication requirements, fallback behavior, and invalid-link handling. If a link opens a protected destination, decide whether to preserve the intended destination after sign-in or redirect to a safe default. Keep that behavior consistent with the rest of the authentication flow.

The React Native deep linking guide is a useful companion when configuring links across development and release builds.

6. Loading, error, and not-found states

Navigation states are part of the route design. For data-backed screens, define what appears while parameters are being read, data is loading, the record does not exist, and the request fails. Avoid rendering an empty screen while a redirect or authentication check is in progress. A stable loading state prevents flashes of protected content and confusing back-stack changes.

Keep route-level failures recoverable where possible. Offer a retry action for temporary data errors, a clear route back to a known destination for missing records, and a sign-in action when access is required.

7. Navigation testing

Write tests around user outcomes rather than implementation details. At minimum, cover opening a detail screen from a list, returning to the list, switching tabs, dismissing a modal, handling an invalid identifier, and opening a representative deep link. Test both a fresh launch and a state in which the app already contains navigation history.

For TypeScript projects, centralize route parameter types and avoid passing loosely typed navigation data. The TypeScript guide for React Native provides broader guidance on strict configuration and safer component boundaries.

What to double-check

  • Back behavior: Android back, the iOS back button, gestures, and explicit close buttons should not produce different results without a clear reason.
  • Parameter ownership: Decide which values belong in the URL, which belong in temporary screen state, and which should be loaded from storage or a server.
  • Authentication redirects: Prevent redirect loops and avoid briefly displaying protected screens while the session is being restored.
  • State restoration: Check whether a route can be reopened after the app is backgrounded or restarted, and make missing data safe to handle.
  • Accessibility: Give navigation controls meaningful labels, preserve logical focus, and do not rely on color alone to communicate the active tab. Use the React Native accessibility checklist during review.
  • Visual consistency: Align headers, tab bars, modals, and dark-mode behavior with the rest of the design system. A shared theme is easier to maintain than route-specific color decisions; see the dark mode guide for a related approach.
  • Performance: Avoid unnecessary work when switching tabs, especially when screens contain long lists or maps. Keep expensive data loading and rendering scoped to the active route where appropriate. The React Native performance guide covers broader optimization checks.

Common mistakes

Putting every screen directly in the root navigator

A flat route tree becomes difficult to reason about as soon as tabs, authentication, and detail flows are added. Group related screens with folders and layouts so ownership is visible from the file structure.

Using tabs as a substitute for hierarchy

Tabs are for switching between primary areas. A product detail, checkout step, or account preference usually belongs in a nested stack rather than as another tab.

Passing complete objects through navigation

Object parameters become stale and can exceed what a link can safely represent. Pass an identifier, load the current record, and handle the record disappearing between navigation and rendering.

Testing only the happy path

Navigation bugs often appear after a cold start, an expired session, a malformed link, or a failed request. Include those states in manual and automated checks.

Mixing routing responsibilities

Keep route decisions in layouts or route guards, data fetching in data hooks or services, and visual presentation in screen components. This separation makes migration and debugging less risky.

When to revisit

Review this navigation checklist before a major feature cycle, before shipping a new tab or authentication flow, and whenever Expo Router, React Native, or a navigation-related dependency changes. Also revisit it when introducing push notifications, universal links, a web target, a new modal pattern, or a substantially different information architecture.

At each review, create a route inventory and compare it with the current product map. Remove obsolete routes, document externally reachable paths, retest cold and warm deep links, and inspect back behavior on both platforms. Run the navigation test suite after changing layouts, route groups, authentication redirects, or parameter names.

A practical final pass is: open every primary tab, follow one complete nested flow, open one dynamic route directly, trigger one modal, sign out and back in, then launch a representative deep link from a clean state. If each path has a clear loading, error, back, and recovery behavior, your React Native navigation structure is ready for the next iteration.

Related Topics

#React Native#Expo Router#Navigation#Deep Linking#App Architecture
N

Native Dev Hub Editorial Team

React Native Editorial Team

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.