Setting up route protection in React Native_
Learn how to set up route protection in a React Native application using Appwrite.

In this guide, we'll walk through implementing protected routes in React Native using a simplified authentication approach with hardcoded values. The implementation uses a straightforward application structure that's easy to follow along with.
While you can start from scratch, we recommend having a basic React Native project already set up. If you need help with the initial setup, refer to our React Native Appwrite SDK Tutorial below:
Prerequisites
Before we begin, you should have:
- A React Native project with Appwrite integration - Follow our quick start guide to set it up
- Basic understanding of React Native and navigation concepts
Step 1: Setting up the file structure
First, we'll separate our routes into two categories: protected (which requires authentication) and public. We'll create this separation by wrapping our protected routes in a folder called (app):
src
├── app
│ ├── _layout.tsx // Root layout
│ └── signin.tsx // Public route
│
└── (app) // Protected routes group
├── _layout.tsx // Protected layout
└── index.tsx // Protected home screen
To protect the routes in our protected route group, we'll add an auth check within the protected route group's _layout.tsx file. For now, we'll use a hardcoded session value to keep things simple:
// app/(app)/_layout.tsx
import { Slot, Redirect} from "expo-router";
export default function AppLayout() {
const session = false
return !session ? <Redirect href="/signin"/> : <Slot/>
}
This is as simple as it gets - we're just blocking users from accessing any route that uses this layout if there's no session. However, in a real scenario, we want to pull the user state from some sort of provider, which we'll set up next.
Step 2: Creating our auth context
Let's create our auth context that we'll use throughout the app:
// app/context/AuthContext.js
import { useContext, createContext, useState, useEffect } from 'react';
import { Text, SafeAreaView } from 'react-native';
const AuthContext = createContext()
const AuthProvider = ({children}) => {
const [user, setUser] = useState(false)
const [session, setSession] = useState(false)
const [loading, setLoading] = useState(true)
const signIn = async () => {}
const signOut = async () => {}
const contextData = {
user,
session,
signIn,
signOut
}
return (
<AuthContext.Provider value={contextData}>
{loading ? <SafeAreaView>
<Text>Loading...</Text>
</SafeAreaView> : children}
</AuthContext.Provider>
)
}
export {AuthContext, AuthProvider}
const useAuth = () => {return useContext(AuthContext)}
export {useAuth}
Step 3: Setting up the root layout
To use our auth context, we'll wrap the root layout with the AuthProvider:
import { Slot } from 'expo-router';
import { AuthProvider } from './context/AuthContext.js';
export default function Root() {
return (
<AuthProvider>
<Slot />
</AuthProvider>
);
}
Step 4: Implementing protected routes
Now let's create our protected layout that will guard our private routes:
// app/(app)/_layout.tsx
import { Slot, Redirect} from "expo-router";
import {useAuth} from '../context/AuthContext.js'
export default function AppLayout() {
const {user, session} = useAuth()
return !session ? <Redirect href="/signin"/> : <Slot/>
}
Step 5: Setting up the sign-in page
Finally, let's handle the case where an authenticated user tries to visit the sign-in page:
// app/signin.tsx
import { Redirect } from 'expo-router'
import { useAuth } from '@/context/AuthContext'
import { SafeAreaView, Text } from 'react-native'
const signin = () => {
const {session} = useAuth()
if (session) return <Redirect href="/"/>
return (
<SafeAreaView>
<Text>signin</Text>
</SafeAreaView>
)
}
export default signin
This completes our implementation of protected routes in React Native. You now have a foundation for managing authenticated and public routes using React Context to handle the global session state.
Now that you have a basic route protection system in place, you can enhance it by implementing actual authentication logic using Appwrite. If you run into any issues or have questions, the Appwrite community on Discord is always ready to help.
More resources
If you would like to learn more about React Native and Appwrite, we have some resources that you should visit:
Group protected routes inside a folder like (app) and keep public routes (sign-in, sign-up) outside it. The route group gets its own _layout.tsx that performs the auth check and redirects to the sign-in screen if there is no active session, so the protection lives in one place instead of every screen.
Inside the protected group's _layout.tsx. Read the session from your auth context and either render the Slot (when authenticated) or Redirect to the sign-in screen (when not). This runs before any child route mounts, so unauthenticated users never see protected content.
Use React Context. Create an AuthProvider that exposes user, session, signIn, and signOut, wrap your root layout with it, and consume the context via a useAuth hook from any screen. This keeps the session in one source of truth and avoids prop drilling.
Track a loading flag in your auth provider that is true until you have finished checking for an existing session on app start. Render a splash or loader while loading is true so users do not see a flicker between public and protected routes during cold start.
Appwrite Auth manages users and sessions on the backend. Your React Native app calls Appwrite to create or restore a session, and you set that session in your auth context. The route protection logic stays the same, only the signIn, signOut, and session-restore methods talk to Appwrite.
Because the route group's layout intercepts any unauthenticated access and redirects to sign-in, deep links into protected routes will also bounce to the sign-in screen. To send users back to the original deep link after login, capture the intended path before redirecting and navigate to it once a session is established.





