Expo Router v4 : Guide Complet de la Navigation par Fichiers en React Native (2026)

Maîtrisez Expo Router v4, le système de navigation par fichiers qui s'impose en 2026. Stack, Tabs, Drawer, routes dynamiques, deep linking et authentification — tout en un seul guide.

Expo Router v4 Guide Complet (2026)

La navigation est l'une des pierres angulaires de toute application mobile. Pendant des années, les développeurs React Native devaient configurer manuellement chaque navigateur, déclarer chaque route et gérer les transitions d'écran à la main avec React Navigation. Avouons-le, c'est l'une de ces tâches répétitives que l'on finit par faire en pilote automatique — mais qui génère des erreurs au moindre changement d'architecture. Expo Router change radicalement cette approche en apportant le routage basé sur les fichiers au monde mobile — exactement comme Next.js l'a fait pour le web.

En 2026, Expo Router v4 est adopté par plus de 71 % des développeurs React Native, selon le State of React Native Survey. Avec l'Expo SDK 55, il est activé par défaut dans tous les nouveaux projets. Ce guide complet vous apprend à maîtriser la navigation par fichiers : Stack, Tabs, Drawer, routes imbriquées, routes dynamiques, deep linking et gestion de l'authentification.

Pourquoi choisir Expo Router en 2026 ?

Avant Expo Router, ajouter un nouvel écran dans React Native nécessitait trois opérations distinctes : créer le composant, l'enregistrer dans un navigateur, puis ajouter les types TypeScript pour les paramètres de route. Expo Router réduit tout cela à une seule action : créer un fichier dans le répertoire app/. C'est simple en apparence, mais l'impact sur la maintenabilité d'un projet de taille réelle est considérable.

  • Zero configuration : la structure de fichiers est la configuration de navigation.
  • Deep linking automatique : chaque écran dispose d'une URL partageablepar défaut.
  • Routes typées : TypeScript détecte les liens cassés à la compilation.
  • Universel : Android, iOS et web partagent la même structure de navigation.
  • Basé sur React Navigation : toute la puissance de React Navigation, sans la verbosité.

Installation et Configuration

Pour créer un nouveau projet Expo avec Expo Router pré-configuré, utilisez la commande suivante :

npx create-expo-app@latest mon-app --template default@sdk-55
cd mon-app
npx expo start

Honnêtement, c'est là que ça devient agréable : en une seule commande, vous avez un projet fonctionnel avec la navigation déjà en place. Pour ajouter Expo Router à un projet existant :

npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar

Mettez ensuite à jour le point d'entrée dans package.json :

{
  "main": "expo-router/entry"
}

Structure de Fichiers : Le Cœur d'Expo Router

Tout fichier placé dans le répertoire app/ devient automatiquement une route. La correspondance est directe : le chemin du fichier est le chemin URL. C'est le principe qui rend Expo Router si intuitif à prendre en main.

app/
├── _layout.tsx          ← Layout racine (obligatoire)
├── index.tsx            ← Route "/"
├── about.tsx            ← Route "/about"
├── (tabs)/
│   ├── _layout.tsx      ← Configuration de la barre d'onglets
│   ├── index.tsx        ← Onglet "Accueil"
│   ├── explorer.tsx     ← Onglet "Explorer"
│   └── profil.tsx       ← Onglet "Profil"
├── produit/
│   ├── [id].tsx         ← Route dynamique "/produit/123"
│   └── index.tsx        ← Route "/produit"
└── +not-found.tsx       ← Page 404

Le fichier _layout.tsx est le composant de mise en page (layout). Il définit le navigateur utilisé et les éléments d'interface partagés entre les routes enfants (en-tête, barre d'onglets, etc.).

Navigation Stack

Le navigateur Stack empile les écrans les uns sur les autres, permettant à l'utilisateur de revenir en arrière. C'est le navigateur racine le plus courant — et souvent le premier que l'on configure dans un nouveau projet.

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Accueil' }} />
      <Stack.Screen name="profil" options={{ title: 'Mon Profil' }} />
      <Stack.Screen
        name="modal"
        options={{ presentation: 'modal', title: 'Modal' }}
      />
    </Stack>
  );
}

Pour naviguer vers un autre écran depuis n'importe quel composant :

import { Link } from 'expo-router';

export default function Accueil() {
  return (
    <Link href="/profil">Voir mon profil</Link>
  );
}

Navigation par Onglets (Tabs)

La navigation par onglets place les répertoires entre parenthèses pour créer des groupes de routes qui n'affectent pas l'URL. Le répertoire (tabs) crée une barre de navigation inférieure.

// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function TabLayout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#007AFF',
        tabBarStyle: { backgroundColor: '#fff' },
      }}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: 'Accueil',
          tabBarIcon: ({ color }) => (
            <Ionicons name="home" size={24} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="explorer"
        options={{
          title: 'Explorer',
          tabBarIcon: ({ color }) => (
            <Ionicons name="search" size={24} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="profil"
        options={{
          title: 'Profil',
          tabBarIcon: ({ color }) => (
            <Ionicons name="person" size={24} color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

En 2026, Expo Router prend en charge les onglets natifs via NativeTabs, qui utilisent les composants natifs de la plateforme pour un rendu parfaitement optimisé sur iOS et Android. C'est particulièrement impressionnant sur iOS 26 avec le nouveau liquid glass effect — la barre d'onglets prend une apparence translucide vraiment soignée.

// app/(tabs)/_layout.tsx — Onglets natifs (SDK 55+)
import { NativeTabs, NativeTabsContent } from 'expo-router/native-tabs';

export default function TabLayout() {
  return (
    <NativeTabs>
      <NativeTabsContent name="index" title="Accueil" systemImage="house.fill" />
      <NativeTabsContent name="explorer" title="Explorer" systemImage="magnifyingglass" />
    </NativeTabs>
  );
}

Navigation avec Tiroir (Drawer)

Le Drawer navigation crée un menu latéral coulissant, idéal pour les applications avec de nombreuses sections. Installez d'abord la dépendance :

npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
// app/(drawer)/_layout.tsx
import { Drawer } from 'expo-router/drawer';

export default function DrawerLayout() {
  return (
    <Drawer
      screenOptions={{
        drawerActiveTintColor: '#007AFF',
        drawerStyle: { backgroundColor: '#f9f9f9', width: 260 },
      }}
    >
      <Drawer.Screen
        name="index"
        options={{ drawerLabel: 'Tableau de bord', title: 'Accueil' }}
      />
      <Drawer.Screen
        name="parametres"
        options={{ drawerLabel: 'Paramètres', title: 'Paramètres' }}
      />
    </Drawer>
  );
}

Pour ouvrir le tiroir depuis un bouton :

import { DrawerActions } from '@react-navigation/native';
import { useNavigation } from 'expo-router';

export default function Header() {
  const navigation = useNavigation();
  return (
    <TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.openDrawer())}>
      <Ionicons name="menu" size={24} />
    </TouchableOpacity>
  );
}

Routes Imbriquées (Nested Routes)

Expo Router excelle dans la gestion des navigations complexes grâce aux layouts imbriqués. Un cas courant — et j'en croise régulièrement dans les projets clients — c'est d'avoir des onglets avec une pile de navigation à l'intérieur de chaque onglet.

app/
├── _layout.tsx              ← Stack racine
├── (tabs)/
│   ├── _layout.tsx          ← Barre d'onglets
│   ├── index.tsx            ← Accueil
│   └── produits/
│       ├── _layout.tsx      ← Stack dans l'onglet Produits
│       ├── index.tsx        ← Liste des produits
│       └── [id].tsx         ← Détail produit
// app/(tabs)/produits/_layout.tsx
import { Stack } from 'expo-router';

export default function ProduitsLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Nos Produits' }} />
      <Stack.Screen name="[id]" options={{ title: 'Détail' }} />
    </Stack>
  );
}

Routes Dynamiques

Les routes dynamiques utilisent des crochets dans le nom du fichier pour capturer des paramètres variables. Le fichier [id].tsx correspond à toute URL de type /produit/42 ou /produit/chaussures-nike. Simple, mais redoutablement efficace.

// app/produit/[id].tsx
import { useLocalSearchParams } from 'expo-router';
import { Text, View } from 'react-native';

export default function ProduitDetail() {
  const { id } = useLocalSearchParams<{ id: string }>();

  return (
    <View>
      <Text>Produit ID : {id}</Text>
    </View>
  );
}

Pour les routes attrape-tout (catch-all), utilisez [...slug].tsx — utile pour les chemins de longueur variable :

// app/docs/[...slug].tsx
const { slug } = useLocalSearchParams<{ slug: string[] }>();
// /docs/guide/installation → slug = ['guide', 'installation']

Navigation Programmatique

Expo Router expose un objet router pour naviguer de façon impérative, indispensable après une action asynchrone (soumission de formulaire, authentification, etc.). En pratique, c'est l'API que vous utiliserez le plus souvent dans vos handlers.

import { router } from 'expo-router';

// Empiler un nouvel écran
router.push('/produit/42');

// Remplacer l'écran actuel (pas de retour en arrière)
router.replace('/tableau-de-bord');

// Revenir en arrière
router.back();

// Naviguer avec des paramètres
router.push({
  pathname: '/produit/[id]',
  params: { id: '42' },
});

Gestion de l'Authentification et Routes Protégées

Un des cas d'usage les plus importants est la protection de routes selon l'état d'authentification. Expo Router gère cela élégamment via les layouts. Combinez cette approche avec l'authentification biométrique avec Expo SecureStore pour une sécurité maximale.

// app/_layout.tsx — Garde d'authentification globale
import { useEffect } from 'react';
import { Stack, useRouter, useSegments } from 'expo-router';
import { useAuthStore } from '@/store/authStore';

export default function RootLayout() {
  const { token } = useAuthStore();
  const segments = useSegments();
  const router = useRouter();

  useEffect(() => {
    const inAuthGroup = segments[0] === '(auth)';

    if (!token && !inAuthGroup) {
      // Utilisateur non connecté → redirection vers login
      router.replace('/(auth)/connexion');
    } else if (token && inAuthGroup) {
      // Utilisateur connecté → redirection vers l'app
      router.replace('/(app)');
    }
  }, [token, segments]);

  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="(auth)" />
      <Stack.Screen name="(app)" />
    </Stack>
  );
}

Structure des répertoires pour une app avec authentification :

app/
├── _layout.tsx          ← Garde d'auth globale
├── (auth)/
│   ├── _layout.tsx      ← Layout auth (Stack simple)
│   ├── connexion.tsx    ← /connexion
│   └── inscription.tsx  ← /inscription
└── (app)/
    ├── _layout.tsx      ← Layout app avec Tabs
    ├── (tabs)/
    │   ├── index.tsx    ← Tableau de bord
    │   └── profil.tsx   ← Profil utilisateur
    └── parametres.tsx   ← Paramètres

Deep Linking

Expo Router configure automatiquement le deep linking pour chaque route. Il suffit de définir le schéma URL dans app.json :

{
  "expo": {
    "scheme": "monapp",
    "web": {
      "bundler": "metro"
    }
  }
}

Une fois configuré, l'URL monapp://produit/42 ouvrira directement l'écran app/produit/[id].tsx avec id = "42". Pour les liens universels (HTTPS sur iOS, App Links sur Android), consultez le guide sur les intégrations natives avancées avec Expo pour comprendre comment connecter vos routes aux capacités de la plateforme.

Routes Typées avec TypeScript

Expo Router génère automatiquement les types TypeScript pour toutes vos routes. Activez cette fonctionnalité dans app.json :

{
  "expo": {
    "experiments": {
      "typedRoutes": true
    }
  }
}

Vous bénéficiez alors de l'autocomplétion et de la vérification de type sur tous les href :

// TypeScript signalera une erreur si /prooduct/42 n'existe pas
<Link href="/produit/42">Voir le produit</Link>

// Paramètres typés
router.push({
  pathname: '/produit/[id]',
  params: { id: '42' }, // TypeScript valide le paramètre
});

Bonnes Pratiques et Astuces pour la Production

  • Utilisez les groupes de routes (group) pour organiser vos fichiers sans impacter les URLs. Idéal pour séparer les sections authentifiées des publiques.
  • Lazy loading : Expo Router charge les routes à la demande en production, réduisant le temps de démarrage initial.
  • Écran de chargement initial : utilisez SplashScreen d'Expo pendant la résolution de l'état d'authentification pour éviter les flashs d'écrans.
  • Transitions personnalisées : configurez animation dans les options de Stack.Screen (slide_from_right, fade, modal, etc.).
  • Évitez les re-renders inutiles : utilisez useLocalSearchParams plutôt que useSearchParams pour limiter les re-renders aux paramètres locaux uniquement.
  • Tests de navigation : exposez votre router dans les tests E2E avec Maestro ou Detox en utilisant les deep links pour naviguer directement vers l'écran à tester.

Un conseil personnel : commencez toujours par définir la structure d'authentification dès le début du projet. Ajouter une garde d'auth après coup dans un projet déjà complexe est nettement plus pénible que de la mettre en place dès le départ.

Migration depuis React Navigation

Si votre projet utilise React Navigation classique, la migration vers Expo Router est progressive. Expo propose un guide officiel de migration. La bonne nouvelle, c'est que vous n'avez pas à tout migrer d'un coup — les points clés :

  1. Créez le répertoire app/ et déplacez-y vos écrans progressivement.
  2. Remplacez les appels à navigation.navigate() par router.push().
  3. Convertissez vos navigateurs manuels en fichiers _layout.tsx.
  4. Testez le deep linking à chaque étape pour vous assurer que les URLs fonctionnent.

Foire aux Questions

Expo Router remplace-t-il complètement React Navigation ?

Non, Expo Router est construit par-dessus React Navigation. Il fournit une couche de routage basée sur les fichiers, mais utilise React Navigation comme moteur de navigation en arrière-plan. Vous pouvez accéder aux APIs React Navigation directement via useNavigation() et useNavigationState() depuis n'importe quel composant.

Puis-je utiliser Expo Router sans le SDK Expo (bare workflow) ?

Expo Router fonctionne dans les projets bare React Native, mais la configuration est plus complexe qu'avec le managed workflow. Vous devez configurer manuellement Metro, Babel et les dépendances natives. Pour les nouveaux projets, il est fortement recommandé d'utiliser le managed workflow d'Expo SDK 55.

Comment gérer les modales avec Expo Router ?

Ajoutez l'option presentation: 'modal' à votre Stack.Screen. Créez un fichier app/modal.tsx et naviguez vers lui avec router.push('/modal'). La modale s'affichera avec l'animation de glissement standard de la plateforme. Pour les modales accessibles depuis plusieurs endroits, utilisez un groupe de routes dédié comme (modals).

Comment protéger des routes qui nécessitent une authentification ?

Utilisez un useEffect dans votre layout racine app/_layout.tsx pour surveiller l'état d'authentification et appeler router.replace() vers la page de connexion si l'utilisateur n'est pas connecté. Organisez vos routes dans des groupes (auth) et (app) pour une séparation claire. Cette approche est réactive : dès que le token expire ou est supprimé, l'utilisateur est automatiquement redirigé.

Expo Router fonctionne-t-il pour les applications web React Native ?

Oui, Expo Router est conçu pour être universel. Sur le web, il utilise React Navigation Web avec le support du bouton précédent du navigateur, des URLs SEO-friendly, et du rendu statique côté serveur (SSR/SSG). Les mêmes fichiers de route fonctionnent sur iOS, Android et dans un navigateur web sans modification, avec la possibilité de créer des variantes spécifiques à une plateforme avec les extensions .ios.tsx, .android.tsx et .web.tsx.

À propos de l'auteur Editorial Team

Our team of expert writers and editors.