Expo Router in React Native: Vollständiger Leitfaden zur dateibasierten Navigation
Expo Router revolutioniert die Navigation in React Native durch dateibasiertes Routing. Umfassender Leitfaden zu Projektstruktur, Tab-Navigation, dynamischen Routen, Typed Routes, Modalen, programmatischer Navigation, Middleware und Routenschutz.

Die Navigation in React Native galt lange als einer der aufwändigsten Aspekte der mobilen Entwicklung. Navigatoren mussten manuell konfiguriert, Bildschirme einzeln registriert und Deep Links separat eingerichtet werden. Expo Router beseitigt diese Komplexität, indem es dateibasiertes Routing in die React-Native-Welt bringt. Das Prinzip ist ebenso einfach wie wirkungsvoll: Jede Datei im app-Verzeichnis wird automatisch zu einer navigierbaren Route. Was Entwickler aus Next.js oder Remix kennen, steht nun auch in nativen Anwendungen zur Verfügung. Seit dem Expo SDK 55 und Expo Router v6 deckt dieses System Android, iOS und das Web gleichermaßen ab, ohne dass plattformspezifischer Code erforderlich wäre. Deep Linking, typisierte Pfade und serverseitige Middleware ergeben sich als natürliche Nebenprodukte dieser Architektur.
Neue Expo-Projekte enthalten Expo Router bereits standardmässig. Mit dem Befehl npx create-expo-app@latest --template default@sdk-55 entsteht ein vollständig vorkonfiguriertes Projekt mit dateibasiertem Routing. Für bestehende Projekte genügt die Installation des Pakets expo-router sowie die Anpassung des Einstiegspunkts in der Projektkonfiguration.
So funktioniert dateibasiertes Routing
Das zentrale Konzept hinter Expo Router lässt sich auf eine Grundregel reduzieren: Dateipfad gleich URL-Pfad. Eine Datei namens app/settings.tsx erzeugt die Route /settings. Eine Datei unter app/profile/edit.tsx wird unter /profile/edit erreichbar. Eine zentrale Routing-Konfiguration, wie sie React Navigation erfordert, entfällt vollständig.
Dieser Ansatz bietet gegenüber der traditionellen manuellen Konfiguration drei entscheidende Vorteile:
- Keine Konfigurationsdateien: Routen existieren automatisch, sobald die entsprechende Datei angelegt wird
- Automatisches Deep Linking: Jeder Bildschirm besitzt eine URL, was das Teilen von Inhalten und das Testen erheblich vereinfacht
- Typisierte Navigation: TypeScript erkennt sämtliche verfügbaren Routen bereits zur Kompilierzeit und verhindert fehlerhafte Links
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 stellt die plattformübergreifende Navigation sicher. Im Web generiert sie ein semantisch korrektes Anchor-Element mit href-Attribut, was der Suchmaschinenoptimierung zugutekommt. Auf nativen Plattformen löst sie eine Stack-Navigation mit den gewohnten Übergangsanimationen aus.
Projektstruktur und Layout-Dateien
Layouts bilden das Rückgrat der Navigationsarchitektur in Expo Router. Jedes Verzeichnis innerhalb von app kann eine eigene _layout.tsx-Datei enthalten, die den Navigationscontainer für alle darin befindlichen Bildschirme definiert. Das Root-Layout umschließt die gesamte Anwendung, während verschachtelte Layouts individuelle Bereiche steuern.
Eine typische Projektstruktur veranschaulicht dieses Prinzip:
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/privacyBesondere Beachtung verdienen die Routengruppen -- Verzeichnisse, deren Namen in runden Klammern stehen. Das Verzeichnis (tabs) erstellt zwar einen Tab-Navigator, beeinflusst aber nicht die URL-Struktur. Die resultierenden Pfade lauten /home, /search und /profile, nicht etwa /(tabs)/home. Dieser Mechanismus erlaubt es, unterschiedliche Navigationsmuster auf verschiedene Anwendungsbereiche anzuwenden, ohne die URLs zu verändern.
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 übernimmt darüber hinaus die Funktion des traditionellen App.tsx als Einstiegspunkt. Hier werden Schriftarten geladen, globale Provider konfiguriert und anwendungsweite Einstellungen vorgenommen. Jeder Bildschirm, der innerhalb dieses Layouts gerendert wird, erbt die definierten Header-Optionen, sofern keine Überschreibungen auf Bildschirmebene vorliegen.
Tab-Navigation implementieren
Tab-Navigatoren gehören zu den am häufigsten eingesetzten Navigationsmustern in mobilen Anwendungen. In Expo Router erfolgt deren Konfiguration über die Tabs-Komponente innerhalb einer Routengruppe. Die Deklarationsreihenfolge der Tabs.Screen-Elemente bestimmt die Anordnung der Tabs in der Navigationsleiste.
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 Datei innerhalb der Routengruppe exportiert eine reguläre React-Komponente. Icons, Beschriftungen und Badges der Tab-Leiste werden über die options-Prop des jeweiligen Tabs.Screen konfiguriert. Durch die Nutzung der @expo/vector-icons-Bibliothek stehen Hunderte vorgefertigte Icons zur Verfügung, die sich nahtlos in das Tab-Layout einfügen.
Dynamische Routen und Routenparameter
Statische Dateipfade reichen selten aus. Dynamische Segmente, gekennzeichnet durch eckige Klammern im Dateinamen, ermöglichen parametrisierte Navigation. Eine Datei [id].tsx fängt ein einzelnes Segment ab, während [...slug].tsx sämtliche verbleibenden Pfadsegmente in einem Array sammelt.
import { View, Text, StyleSheet } from 'react-native'
import { useLocalSearchParams, Stack } from 'expo-router'
export default function ProductScreen() {
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' },
})Beim Aufruf von /product/42 rendert dieser Bildschirm mit dem Wert "42" für die Variable id. Der Hook useLocalSearchParams liefert typisierten Zugriff auf alle URL-Parameter und stellt sicher, dass die erwarteten Parametertypen eingehalten werden.
Catch-All-Routen erfassen variable Pfadtiefen und eignen sich besonders für Dokumentationssysteme oder verschachtelte Kategorie-Strukturen:
import { useLocalSearchParams } from 'expo-router'
export default function DocsScreen() {
const { slug } = useLocalSearchParams<{ slug: string[] }>()
return <DocViewer path={slug.join('/')} />
}Der Pfad /docs/getting-started/installation erzeugt ein Array ['getting-started', 'installation'], das beliebig weiterverarbeitet werden kann. Diese Flexibilität macht Catch-All-Routen zur bevorzugten Wahl, wenn die Tiefe der URL-Hierarchie nicht im Voraus feststeht.
Bereit für deine React Native-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Typed Routes: Typsicherheit zur Kompilierzeit
Ein häufiges Problem in Navigationssystemen sind fehlerhafte Routen-Strings, die erst zur Laufzeit auffallen -- oft in Produktivumgebungen. Expo Router bietet mit Typed Routes eine Lösung, die TypeScript-Typen automatisch aus der vorhandenen Dateistruktur generiert. Ungültige Links werden so bereits beim Kompilieren als Fehler markiert.
Die Aktivierung erfolgt über die Projektkonfiguration in app.json:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Sobald diese Option aktiv ist, akzeptieren sowohl die href-Prop der Link-Komponente als auch router.push() ausschließlich Strings, die tatsächlich existierenden Routen entsprechen:
import { router } from 'expo-router'
function handleCheckout(cartId: string) {
router.push(`/product/${cartId}`)
}Die Kombination aus Typed Routes und useLocalSearchParams garantiert, dass Parameternamen in der Routendefinition und im konsumierenden Komponent übereinstimmen. Wird eine Routendatei umbenannt oder gelöscht, meldet TypeScript sofort alle veralteten Referenzen. In Projekten mit Dutzenden oder Hunderten von Bildschirmen spart diese Absicherung erheblich Zeit bei der Fehlersuche.
Modale Bildschirme und Präsentationsoptionen
Modale gehören zum Standardrepertoire mobiler Oberflächen. In Expo Router werden modale Bildschirme als gewöhnliche Routen behandelt, die im übergeordneten Layout mit der Option presentation: 'modal' konfiguriert werden. Die Dateikonvention bleibt gewahrt: Ein Modal ist nichts anderes als eine Route mit besonderer Darstellungsform.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen
name="create-post"
options={{
presentation: 'modal',
headerTitle: 'New Post',
}}
/>
</Stack>
)
}Der zugehörige Bildschirm wird als reguläre Komponente implementiert. router.back() schließt das Modal und führt den Benutzer zum vorherigen Bildschirm im Navigationsstapel zurück:
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 = () => {
router.back()
}
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,
},
})Neben dem Standard-Modal unterstützt Expo Router die Varianten transparentModal, fullScreenModal und containedModal. Jede Variante unterscheidet sich in Animationsverhalten und Darstellung, wobei die plattformspezifischen Konventionen von iOS und Android respektiert werden.
Programmatische Navigation und die Router-API
Die deklarative Link-Komponente deckt die meisten Anwendungsfälle ab. Situationen, in denen die Navigation durch Geschäftslogik gesteuert wird -- etwa nach einem erfolgreichen Login, dem Absenden eines Formulars oder dem Ablauf eines Timers -- erfordern jedoch die imperative Router-API.
import { router } from 'expo-router'
router.push('/profile/settings')
router.replace('/login')
router.back()
router.push({
pathname: '/product/[id]',
params: { id: '42', source: 'recommendations' },
})
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 spielt in Authentifizierungsabläufen eine besondere Rolle. Nach einer erfolgreichen Anmeldung verhindert router.replace('/dashboard'), dass Benutzer über die Zurück-Taste zum Login-Bildschirm gelangen. Die Methode router.canGoBack() ermöglicht darüber hinaus die bedingte Anzeige von Zurück-Schaltflächen, was insbesondere in tiefen Navigationshierarchien die Benutzererfahrung verbessert.
router.replace() ersetzt den aktuellen Eintrag im Navigationsverlauf. Für Authentifizierungswächter, die nicht angemeldete Benutzer umleiten sollen, eignet sich die Komponente <Redirect href="/login" /> besser. Sie greift bereits während der Renderphase und arbeitet korrekt mit dem serverseitigen Rendering im Web zusammen.
Middleware und Routenschutz
Expo Router v6 führt serverseitige Middleware ein, die Anfragen abfängt, bevor sie den eigentlichen Routenkomponenten erreichen. Die Datei +middleware.ts im app-Verzeichnis dient als zentraler Punkt für Authentifizierungsprüfungen, Weiterleitungen und HTTP-Header-Manipulationen.
import { type MiddlewareRequest } from 'expo-router/server'
export function middleware(request: MiddlewareRequest) {
const { pathname } = request.nextUrl
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
}Auf nativen Plattformen steht die serverseitige Middleware nicht zur Verfügung. Der Routenschutz muss dort über clientseitige Wächter in den Layout-Komponenten umgesetzt werden. Das bewährteste Muster besteht darin, geschützte Routengruppen mit einer Authentifizierungsprüfung zu versehen:
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 />
}Dieses Muster stellt sicher, dass kein geschützter Bildschirm gerendert wird, solange die Authentifizierung nicht abgeschlossen ist. Die Redirect-Komponente von Expo Router leitet den Benutzer um, bevor der geschützte Inhalt in den Komponentenbaum eingehängt wird.
Die Server-Middleware ist ausschließlich im Web mit serverseitigem Rendering verfügbar. Auf nativen Plattformen müssen clientseitige Wächter in den Layout-Komponenten implementiert werden. Nur die Kombination beider Strategien gewährleistet einen lückenlosen Routenschutz über alle Plattformen hinweg.
Fazit
Expo Router v6 überführt die Konventionen moderner Web-Frameworks in die React-Native-Welt und schafft ein einheitliches Navigationsmodell für mobile und Web-Plattformen. Die wichtigsten Erkenntnisse im Überblick:
- Expo Router ersetzt die manuelle Navigationskonfiguration durch dateibasierte Konventionen -- das Anlegen einer Datei im
app-Verzeichnis genügt, um eine neue Route zu erzeugen _layout.tsx-Dateien definieren Navigationshierarchien mit Stacks, Tabs und Drawern, ohne dass eine zentrale Konfigurationsdatei erforderlich ist- Dynamische Routen mit
[param].tsxund Catch-All-Routen mit[...slug].tsxermöglichen parametrisierte Navigation mit vollständiger TypeScript-Unterstützung - Typed Routes erkennen ungültige Navigationslinks bereits zur Kompilierzeit, sobald die entsprechende Option in
app.jsonaktiviert ist - Modale Bildschirme, programmatische Navigation über
router.push/replace/backund Server-Middleware runden das Routing-Werkzeugset ab - Routengruppen in runden Klammern strukturieren den Code, ohne die URL-Hierarchie zu beeinflussen, und bewahren die Übersichtlichkeit auch in wachsenden Projekten
- Clientseitige Wächter in Layouts sichern native Routen ab, Server-Middleware übernimmt den Schutz im Web -- die Kombination beider Ansätze garantiert plattformübergreifende Sicherheit
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
