Skip to main content
Docs

React Router Quickstart

React Router can be used in different modes: declarative, data, or framework. This tutorial explains how to use React Router in framework mode. To use React Router in declarative mode instead, see the dedicated guide.

This tutorial assumes that you're using React Router v7.1.2 or later in framework mode.

Install @clerk/react-router

The Clerk React Router SDK provides prebuilt components, hooks, and helpers to make it easy to integrate authentication and user management in your React Router app.

Run the following command to install the SDK:

terminal
npm install @clerk/react-router
terminal
yarn add @clerk/react-router
terminal
pnpm add @clerk/react-router
terminal
bun add @clerk/react-router
.env
VITE_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
CLERK_SECRET_KEY=YOUR_SECRET_KEY

Add clerkMiddleware() and rootAuthLoader() to your app

clerkMiddleware() grants you access to user authentication state throughout your app.

React Router middleware requires opting in via a future flag. Add the following to your react-router.config.ts file:

react-router.config.ts
import type { Config } from '@react-router/dev/config'

export default {
  // ...
  future: {
    v8_middleware: true,
  },
} satisfies Config

Then, add the following code to your root.tsx file to configure the clerkMiddleware() and rootAuthLoader() functions.

To load additional data or configure options, see the clerkMiddleware() reference.

app/root.tsx
3 lines collapsedimport { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' import type { Route } from './+types/root' import stylesheet from './app.css?url'
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server' export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args)
62 lines collapsedexport const links: Route.LinksFunction = () => [ { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous', }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', }, { rel: 'stylesheet', href: stylesheet }, ] export function Layout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <Meta /> <Links /> </head> <body> {children} <ScrollRestoration /> <Scripts /> </body> </html> ) } export default function App() { return <Outlet /> } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { let message = 'Oops!' let details = 'An unexpected error occurred.' let stack: string | undefined if (isRouteErrorResponse(error)) { message = error.status === 404 ? '404' : 'Error' details = error.status === 404 ? 'The requested page could not be found.' : error.statusText || details } else if (import.meta.env.DEV && error && error instanceof Error) { details = error.message stack = error.stack } return ( <main className="pt-16 p-4 container mx-auto"> <h1>{message}</h1> <p>{details}</p> {stack && ( <pre className="w-full p-4 overflow-x-auto"> <code>{stack}</code> </pre> )} </main> ) }

Add <ClerkProvider> and Clerk components to your app

The <ClerkProvider> component provides session and user context to Clerk's hooks and components. It's recommended to wrap your entire app at the entry point with <ClerkProvider> to make authentication globally accessible. See the reference docs for other configuration options.

It's required to pass loaderData to the <ClerkProvider> component. This data is provided by the rootAuthLoader() function.

The following example adds <ClerkProvider> and creates a header using the following Clerk components:

app/root.tsx
import { ClerkProvider, SignedIn, SignedOut, UserButton, SignInButton } from '@clerk/react-router'
41 lines collapsedimport { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server' import type { Route } from './+types/root' import stylesheet from './app.css?url' export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args) export const links: Route.LinksFunction = () => [ { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous', }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', }, { rel: 'stylesheet', href: stylesheet }, ] export function Layout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <Meta /> <Links /> </head> <body> {children} <ScrollRestoration /> <Scripts /> </body> </html> ) }
// Pull in the `loaderData` from the `rootAuthLoader()` function export default function App({ loaderData }: Route.ComponentProps) { return ( // Pass the `loaderData` to the `<ClerkProvider>` component <ClerkProvider loaderData={loaderData}> <header className="flex items-center justify-center py-8 px-4"> {/* Show the sign-in button when the user is signed out */} <SignedOut> <SignInButton /> </SignedOut> {/* Show the user button when the user is signed in */} <SignedIn> <UserButton /> </SignedIn> </header> <main> <Outlet /> </main>
26 lines collapsed </ClerkProvider> ) } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { let message = 'Oops!' let details = 'An unexpected error occurred.' let stack: string | undefined if (isRouteErrorResponse(error)) { message = error.status === 404 ? '404' : 'Error' details = error.status === 404 ? 'The requested page could not be found.' : error.statusText || details } else if (import.meta.env.DEV && error && error instanceof Error) { details = error.message stack = error.stack } return ( <main className="pt-16 p-4 container mx-auto"> <h1>{message}</h1> <p>{details}</p> {stack && ( <pre className="w-full p-4 overflow-x-auto"> <code>{stack}</code> </pre>
)} </main> ) }

Create your first user

Run your project with the following command:

terminal
npm run dev
terminal
yarn dev
terminal
pnpm dev
terminal
bun dev

Visit your app's homepage at http://localhost:5173. Sign up to create your first user.

Create a custom sign-in-or-up page

Learn how add custom sign-in-or-up page with Clerk components.

Read session and user data

Learn how to use Clerk's hooks and helpers to access the session and user data in your React Router app.

Declarative mode

Learn how to use Clerk with React Router in declarative mode to add authentication to your application.

Feedback

What did you think of this content?

Last updated on