# React Navigation is properly initialized

- **Pattern:** `ab-001852` (`mobile-navigation-linking.navigation-structure.nav-init`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001852
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001852)

## Why it matters

Without a single NavigationContainer at the root, React Navigation has no scene graph to mount — screens render as disconnected components, deep links resolve to nothing, and the back button bubbles to the OS and closes the app. Users who tap a push notification or share-sheet link land on a blank route or a cold Home, destroying the user-experience contract the rest of the app depends on. Duplicated containers create competing state trees that silently drop navigation events.

## Severity rationale

Critical because a missing or duplicated NavigationContainer breaks every downstream routing, linking, and state-restoration feature app-wide.

## Remediation

Mount exactly one `NavigationContainer` at the app root and pass it a `linking` config. Put this in `App.tsx` so every screen is a descendant:

```tsx
import { NavigationContainer } from '@react-navigation/native'

export default function App() {
  return (
    <NavigationContainer linking={linking}>
      <RootNavigator />
    </NavigationContainer>
  )
}
```

Delete any secondary `NavigationContainer` instances — nested ones must be replaced by plain `Navigator` components.

## Detection

- **ID:** `nav-init`
- **Severity:** `critical`
- **What to look for:** Examine your root navigation setup. Look for `NavigationContainer` from `@react-navigation/native` wrapping your app. Check for linking configuration passed to `NavigationContainer`. In Expo projects, this is typically in `App.tsx` or a root navigation file.
- **Pass criteria:** Count all `NavigationContainer` instances in the codebase. Exactly 1 `NavigationContainer` must be configured at the root of your app, with a ref or linking config. A `linking` config must be passed to `NavigationContainer` (either inline or as a separate object). The app structure follows React Navigation conventions. Report even on pass: "Found X NavigationContainer instances, linking config with Y prefixes."
- **Fail criteria:** `NavigationContainer` is missing, duplicated (no more than 1 is allowed), or does not wrap the full app tree. Linking config is missing entirely. Do NOT pass when navigation is implemented with conditional renders or state-based screen switching instead of React Navigation or Expo Router.
- **Skip (N/A) when:** Never — every React Native app needs navigation initialization.
- **Cross-reference:** The Mobile Offline & Storage audit (`mobile-offline-storage`) checks state persistence that intersects with NavigationContainer's onStateChange handling.
- **Detail on fail:** Describe what's wrong. Example: `"NavigationContainer wraps only a subset of the app tree, not the root"` or `"No linking config passed to NavigationContainer"`
- **Remediation:** Your app's navigation must be initialized with `NavigationContainer` at the root. In `App.tsx`:

  ```tsx
  import { NavigationContainer } from '@react-navigation/native'
  import { createNativeStackNavigator } from '@react-navigation/native-stack'

  const Stack = createNativeStackNavigator()

  export default function App() {
    return (
      <NavigationContainer linking={linking}>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Details" component={DetailsScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    )
  }
  ```

  Define your `linking` config object (see deep linking checks below) and pass it to `NavigationContainer`.

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-001852
