Expo Router in React Native: Vollständiger Leitfaden zur dateibasierten Navigation
Expo Router für React Native: dateibasiertes Routing, Layouts, dynamische Routen, typisierte Navigation, Tabs, Modals, Middleware und SDK 56 Migration.

Expo Router bringt dateibasiertes Routing nach React Native und ersetzt die manuelle Navigationskonfiguration durch einen konventionsgetriebenen Ansatz, der von Next.js inspiriert ist. Seit dem Expo SDK 57 und Expo Router erfordert die Entwicklung plattformübergreifender Navigation für Android, iOS und das Web nichts weiter als das Erstellen von Dateien im richtigen Verzeichnis.
Neue Expo-Projekte werden mit vorkonfiguriertem Expo Router ausgeliefert. Mit dem Befehl npx create-expo-app@latest --template default entsteht ein Projekt mit dateibasiertem Routing direkt einsatzbereit. Für bestehende Projekte genügt die Installation des Pakets expo-router sowie die Anpassung des Einstiegspunkts in der Projektkonfiguration.
So funktioniert dateibasiertes Routing in Expo Router
Jede Datei innerhalb des app-Verzeichnisses wird automatisch zu einer Route. Der Dateipfad entspricht direkt dem URL-Pfad, sodass keine zentrale Navigationskonfiguration erforderlich ist. Eine Datei unter app/settings.tsx erzeugt die Route /settings, während app/profile/edit.tsx auf /profile/edit abgebildet wird.
Dieser Ansatz bietet drei wesentliche Vorteile gegenüber dem traditionellen React-Navigation-Setup:
- Keine Konfiguration: Routen existieren, sobald eine Datei erstellt wird
- Automatisches Deep Linking: Jeder Bildschirm erhält eine URL, was das Teilen und Testen ermöglicht
- Typsichere Navigation: TypeScript kennt die vorhandenen Routen bereits zur Kompilierzeit
import { View, Text, StyleSheet } from 'react-native'
import { Link } from 'expo-router'
export default function HomeScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome</Text>
{/* Link maps directly to file path */}
<Link href="/settings" style={styles.link}>
Open Settings
</Link>
<Link href="/profile/edit" style={styles.link}>
Edit Profile
</Link>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 24 },
title: { fontSize: 28, fontWeight: 'bold', marginBottom: 16 },
link: { fontSize: 16, color: '#61DAFB', marginTop: 12 },
})Die Link-Komponente übernimmt die Navigation auf allen Plattformen. Im Web rendert sie ein Anchor-Tag mit korrekten href-Attributen für SEO. Auf nativen Plattformen löst sie eine Stack-basierte Navigation aus.
Projektstruktur und Layout-Dateien
Expo Router verwendet _layout.tsx-Dateien zur Definition von Navigationscontainern. Jedes Verzeichnis kann sein eigenes Layout besitzen, wodurch verschachtelte Navigationshierarchien entstehen. Das Root-Layout umschließt die gesamte App, während verschachtelte Layouts spezifische Bereiche steuern.
Eine typische Projektstruktur sieht folgendermaßen aus:
app/
_layout.tsx # Root layout (Stack or custom)
index.tsx # Home screen (/)
(tabs)/ # Tab group (parentheses = route group)
_layout.tsx # Tab navigator
home.tsx # /home tab
search.tsx # /search tab
profile.tsx # /profile tab
settings/
_layout.tsx # Settings stack layout
index.tsx # /settings
notifications.tsx # /settings/notifications
privacy.tsx # /settings/privacyRoutengruppen, also Verzeichnisse in runden Klammern, organisieren Dateien ohne Auswirkung auf die URL. Das Verzeichnis (tabs) oben erstellt einen Tab-Navigator, aber die URLs bleiben /home, /search und /profile statt /tabs/home.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: '#1a1a2e' },
headerTintColor: '#ffffff',
headerTitleStyle: { fontWeight: '600' },
}}
>
<Stack.Screen name="index" options={{ title: 'Home' }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="settings" options={{ title: 'Settings' }} />
</Stack>
)
}Das Root-Layout dient auch als Ort zum Laden von Schriften, Initialisieren von Providern und Konfigurieren globaler Einstellungen.
Tab-Navigation mit Expo Router erstellen
Tab-Navigation erfordert eine _layout.tsx-Datei innerhalb einer Routengruppe. Expo Router bietet sowohl NativeTabs für plattformspezifische Tab-Erlebnisse als auch die Standard-Tabs-Komponente für die meisten Anwendungsfälle. Seit SDK 56 unterstützt NativeTabs die Eigenschaft disabled, um die Tab-Auswahl zu verhindern, während die Tabs sichtbar bleiben.
import { Tabs } from 'expo-router'
import { Ionicons } from '@expo/vector-icons'
export default function TabLayout() {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: '#61DAFB',
tabBarInactiveTintColor: '#888',
tabBarStyle: {
backgroundColor: '#1a1a2e',
borderTopColor: '#2d2d44',
},
}}
>
<Tabs.Screen
name="home"
options={{
title: 'Home',
tabBarIcon: ({ color, size }) => (
<Ionicons name="home" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="search"
options={{
title: 'Search',
tabBarIcon: ({ color, size }) => (
<Ionicons name="search" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profile',
tabBarIcon: ({ color, size }) => (
<Ionicons name="person" size={size} color={color} />
),
}}
/>
</Tabs>
)
}Jede Tab-Bildschirmdatei exportiert eine Standard-React-Komponente. Das Tab-Bar-Icon, die Beschriftung und das Badge werden über die options-Prop im Layout konfiguriert.
Dynamische Routen und Routenparameter
Dynamische Segmente verwenden eckige Klammern im Dateinamen. Eine Datei namens [id].tsx erfasst ein einzelnes Segment, während [...slug].tsx alle verbleibenden Segmente auffängt.
import { View, Text, StyleSheet } from 'react-native'
import { useLocalSearchParams, Stack } from 'expo-router'
export default function ProductScreen() {
// Extract the dynamic parameter from the URL
const { id } = useLocalSearchParams<{ id: string }>()
return (
<View style={styles.container}>
<Stack.Screen options={{ title: \`Product \${id}\` }} />
<Text style={styles.heading}>Product Details</Text>
<Text style={styles.id}>ID: {id}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
heading: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 },
id: { fontSize: 16, color: '#888' },
})Die Navigation zu /product/42 rendert diesen Bildschirm mit id auf "42" gesetzt. Der Hook useLocalSearchParams bietet typisierten Zugriff auf alle Routenparameter.
Für Catch-all-Routen erfasst [...slug].tsx vollständige Pfadsegmente:
import { useLocalSearchParams } from 'expo-router'
export default function DocsScreen() {
// /docs/getting-started/installation → slug = ['getting-started', 'installation']
const { slug } = useLocalSearchParams<{ slug: string[] }>()
return <DocViewer path={slug.join('/')} />
}Bereit für deine React Native-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Typisierte Routen für Kompilierzeit-Sicherheit
Expo Router generiert automatisch Routentypen, wenn typed routes aktiviert ist. Dies erkennt defekte Links zur Kompilierzeit statt zur Laufzeit.
Typisierte Routen in app.json aktivieren:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Nach der Aktivierung akzeptiert die href-Prop auf Link und das Argument für router.push() nur gültige Routenstrings:
import { router } from 'expo-router'
function handleCheckout(cartId: string) {
// TypeScript validates this route exists
router.push(\`/product/\${cartId}\`)
// This would cause a compile error if /nonexistent doesn't exist
// router.push('/nonexistent')
}Typisierte Routen harmonieren gut mit useLocalSearchParams. Die generierten Typen stellen sicher, dass Parameternamen zwischen der Routendefinition und der konsumierenden Komponente übereinstimmen, wodurch subtile Bugs vermieden werden, die sonst erst beim Navigieren zu einem bestimmten Bildschirm auftreten würden.
Modale Bildschirme und Präsentationsoptionen
Modals in Expo Router sind reguläre Bildschirme, die mit presentation: 'modal' im Layout konfiguriert werden. Dieser Ansatz behält die dateibasierte Konvention bei: Ein Modal ist einfach eine weitere Route.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
{/* Modal screen slides up from the bottom */}
<Stack.Screen
name="create-post"
options={{
presentation: 'modal',
headerTitle: 'New Post',
}}
/>
</Stack>
)
}import { View, TextInput, Button, StyleSheet } from 'react-native'
import { router } from 'expo-router'
import { useState } from 'react'
export default function CreatePostModal() {
const [title, setTitle] = useState('')
const handleSubmit = () => {
// Submit logic here
router.back() // Dismiss the modal
}
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Post title"
value={title}
onChangeText={setTitle}
/>
<Button title="Publish" onPress={handleSubmit} />
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
input: {
borderWidth: 1,
borderColor: '#333',
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 16,
},
})Die Navigation zu /create-post löst die modale Präsentation aus. Der Aufruf von router.back() schließt das Modal und kehrt zum vorherigen Bildschirm im Stack zurück.
Programmatische Navigation und die Router-API
Über die Link-Komponente hinaus bietet Expo Router eine imperative API über das router-Objekt. Diese behandelt Navigation, die durch Geschäftslogik statt durch Benutzereingaben ausgelöst wird.
import { router } from 'expo-router'
// Push a new screen onto the stack
router.push('/profile/settings')
// Replace the current screen (no back button)
router.replace('/login')
// Go back to the previous screen
router.back()
// Navigate with parameters
router.push({
pathname: '/product/[id]',
params: { id: '42', source: 'recommendations' },
})
// Check if going back is possible
import { useRouter } from 'expo-router'
function BackButton() {
const router = useRouter()
return router.canGoBack() ? (
<Button title="Back" onPress={() => router.back()} />
) : null
}Die Unterscheidung zwischen router.push und router.replace ist wichtig für Authentifizierungsabläufe in React Native. Nach einer erfolgreichen Anmeldung verhindert router.replace('/dashboard'), dass der Benutzer zum Login-Bildschirm zurücknavigieren kann.
router.replace() ersetzt den aktuellen Eintrag im Navigationsverlauf. Für Authentifizierungswächter, die nicht authentifizierte Benutzer umleiten, sollte <Redirect href="/login" /> innerhalb des Komponenten-Renders verwendet werden: Es wird während der Render-Phase ausgelöst und funktioniert korrekt mit serverseitigem Rendering im Web.
Middleware und Routenschutz
Expo Router bietet Server-Middleware für Logik auf Routenebene. Die Datei +middleware.ts fängt Anfragen ab, bevor sie die Routenkomponente erreichen, und ermöglicht Authentifizierungsprüfungen, Weiterleitungen und Header-Manipulation.
import { type MiddlewareRequest } from 'expo-router/server'
export function middleware(request: MiddlewareRequest) {
const { pathname } = request.nextUrl
// Protect dashboard routes
const protectedPaths = ['/dashboard', '/settings', '/profile']
const isProtected = protectedPaths.some(p => pathname.startsWith(p))
if (isProtected) {
const token = request.cookies.get('session')
if (!token) {
return Response.redirect(new URL('/login', request.url))
}
}
return undefined // Continue to route
}Auf nativen Plattformen, auf denen Server-Middleware nicht läuft, basiert der Routenschutz auf clientseitigen Wächtern. Ein gängiges Muster umhüllt geschützte Layouts mit einer Authentifizierungsprüfung:
import { Redirect, Stack } from 'expo-router'
import { useAuth } from '@/hooks/useAuth'
export default function AuthenticatedLayout() {
const { isLoggedIn, isLoading } = useAuth()
if (isLoading) return null
if (!isLoggedIn) return <Redirect href="/login" />
return <Stack />
}Server-Middleware läuft nur im Web mit serverseitigem Rendering. Für native Apps sollten clientseitige Routenwächter in Layout-Komponenten implementiert werden. Die Kombination beider Ansätze gewährleistet konsistenten Schutz auf allen Plattformen.
SDK 56 Migration: React Navigation Fork
Ab dem Expo SDK 56 hängt Expo Router nicht mehr von den @react-navigation/*-Paketen ab. Falls das Projekt direkt aus React Navigation importiert, müssen die Imports aktualisiert werden:
| Ursprüngliches Paket | Neuer Speicherort |
|---|---|
@react-navigation/native | expo-router/react-navigation |
@react-navigation/stack | expo-router/js-stack |
@react-navigation/bottom-tabs | expo-router/js-tabs |
Der Codemod aktualisiert die Imports automatisch:
npx expo-codemod sdk-56-expo-router-react-navigation-replace srcDie Laufzeit-API bleibt unverändert. Nur die Modulspezifizierer wurden verschoben. Drittanbieter-Bibliotheken, die weiterhin aus @react-navigation/core importieren, funktionieren automatisch, da Expo CLI diese Imports während des Bundlings umschreibt.
Quellen
- Expo Router Dokumentation - offizieller Leitfaden und API-Referenz
- Expo SDK 57 Changelog - aktuelle stabile Release-Notes
- Expo Router v56 Blogbeitrag - Erklärung zum React Navigation Fork
- SDK 55 zu 56 Migrationsanleitung - Import-Migrationsschritte
Was Interviewer über Expo Router erwarten
- Expo Router bildet jede Datei im
app-Verzeichnis automatisch auf eine Route ab und eliminiert die manuelle Navigationskonfiguration - Layouts, definiert durch
_layout.tsx-Dateien, erstellen Navigationshierarchien für Stacks, Tabs und Drawers - Dynamische Routen mit
[param].tsxund Catch-all-Routen mit[...slug].tsxhandhaben parametrisierte Navigation mit vollständiger TypeScript-Unterstützung - Typisierte Routen erkennen defekte Navigationslinks zur Kompilierzeit, wenn sie in
app.jsonaktiviert sind - Modale Bildschirme, programmatische Navigation über
router.push/replace/backund Server-Middleware vervollständigen das Routing-Toolkit - Routengruppen mit Klammern in Verzeichnisnamen organisieren Code ohne Auswirkung auf URLs
- Clientseitige Routenwächter in Layouts übernehmen die Authentifizierung auf nativen Plattformen, während Server-Middleware das Web abdeckt
- Seit SDK 56 müssen Imports aus
@react-navigation/*aufexpo-router/*-Äquivalente aktualisiert werden
Für mehr zu React Native Architektur und Interviewvorbereitung siehe das Native-Module-Modul.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Findest du den Bug in React Native?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 6. Oktober 2026
Tags
Teilen
Verwandte Artikel

React Native 0.87 und SwiftPM 2026: Modernes iOS-Build-System und Interviewfragen
React Native 0.87 bringt experimentelle Swift Package Manager-Unterstützung für iOS-Builds. Dieser Leitfaden behandelt SwiftPM-Einrichtung, die Strict TypeScript API, Metro 0.87-Optimierungen und Interviewfragen für Senior Mobile-Entwickler.

Hermes V1 in React Native 0.84: Performance, Bytecode-Vorkompilierung und Fragen für technische Interviews
Eine tiefgehende Analyse von Hermes V1 als Standard-JavaScript-Engine in React Native 0.84. Dieser Artikel behandelt Bytecode-Vorkompilierung, den Hades Concurrent Garbage Collector, Memory-Optimierungsstrategien und technische Interviewfragen.

React Native 0.86 im Jahr 2026: Edge-to-Edge Android, DevTools und Interviewfragen
React Native 0.86 mit Edge-to-Edge Support für Android 15+, DevTools Verbesserungen und praktischen Interviewfragen. Vollständiger Leitfaden mit Codebeispielen.