React Router Quickstart - Getting started | Clerk Docs

React Router Quickstart

Hand this prompt to your agent to add auth to your app with the Clerk CLI. No need to leave your terminal or copy and paste API keys.

Add Clerk Authentication

Use the Clerk CLI to add authentication. In agent environments, supported frameworks default to accountless setup: npx -y clerk@latest init provisions a claimable application and writes temporary development keys without requiring a Clerk account.

Before you start

Show the user this checklist and wait for a yes:

Here's what I'll do to get you set up with Clerk.

1. Set up Clerk in this project, or scaffold a new app if this directory is empty
2. Start your app with Clerk installed.

Shall I proceed?

Existing authentication

Before init, inspect auth dependencies, routes, middleware, sessions, and user records. If auth already exists, stop and propose a migration plan covering:

Migration guide: https://clerk.com/docs/guides/development/migrating/overview

Step 1a: Existing project

From the project root:

npx -y clerk@latest init

init detects the framework and package manager, installs the SDK, and applies framework setup — provider, middleware, auth routes, env. Do not pass --framework or --pm unless the user wants to override detection. Do not list apps or ask which Clerk app to use.

Step 1b: Empty directory

Ask which framework and package manager to use, defaulting to Next.js and npm:

npx -y clerk@latest init --framework <framework> --pm <package-manager>

If a lockfile is present, let it pick the package manager: pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lock or bun.lockb -> bun, package-lock.json -> npm.

Step 1c: Accountless development keys

For a signed-out user on a supported framework, init provisions a claimable application and writes temporary keys to the detected environment file. Relay the filename and claim instruction printed by the CLI. The app stays unclaimed until the user runs npx -y clerk@latest auth login; don't run it unless asked. Use --accountless only to force this flow while signed in.

Frameworks without accountless support need real API keys. There, init applies what setup it can and prints the remaining steps.

To link an existing Clerk application, add --app <application_id> — but only when the user supplies the ID. If they want to link and have no ID, run npx -y clerk@latest apps list --json, show the names and IDs, and ask. Never choose an application for them.

Step 2: Fall back to docs when init is incomplete

If init reports the framework is unsupported or undetected, follow the quickstart instead.

init scaffolds Next.js, React, React Router, Nuxt, TanStack Start, Astro, Vue, JavaScript/Vite, Expo, Express, Fastify, iOS, and Android.

Step 3: Add visible auth controls

The app needs sign-in, sign-up, and signed-in user controls, worked into the existing layout or navigation. If they already exist, adapt them instead of duplicating.

For Next.js App Router:

import { SignInButton, SignUpButton, Show, UserButton } from '@clerk/nextjs'

<>
<Show when="signed-out">
    <SignInButton />
    <SignUpButton />
</Show>
<Show when="signed-in">
    <UserButton />
</Show>
</>

Step 4: Verify

npx -y clerk@latest doctor

Then start the app, confirm the auth controls render, and fix anything the CLI reports.

Step 5: If using shadcn/ui

If components.json exists in the project root, add @clerk/ui with the package manager from Step 1 — npm install, pnpm add, yarn add, or bun add.

Apply the theme in your provider:

import { shadcn } from '@clerk/ui/themes'

<ClerkProvider appearance={{ theme: shadcn }}>{children}</ClerkProvider>

Add to global CSS:

@import '@clerk/ui/themes/shadcn.css';

Critical rules

Docs: https://clerk.com/docs/cli https://clerk.com/docs/llms.txt

After setup

Have the user sign up as their first test user. Congratulate them once the profile icon appears in the nav.

Before production, have the user claim the app with npx -y clerk@latest auth login, then configure production with npx -y clerk@latest deploy. Unclaimed apps and temporary keys aren't production-ready.

Then offer Organizations — multi-tenancy, team invitations, roles and permissions, and enterprise SSO.

If yes:

  1. Run npx -y clerk@latest enable orgs.
  2. Add <OrganizationSwitcher /> next to the existing <UserButton />, or the framework equivalent.
  3. Have them create an organization from the switcher and invite a teammate.

If no, point them to Organizations (https://clerk.com/docs/guides/organizations/overview), Components (https://clerk.com/docs/reference/components/overview), and the Dashboard (https://dashboard.clerk.com/).

Expand prompt

Or set up Clerk yourself by following the step-by-step instructions.

React Router Modes

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.9.0 or later, or v8.3.0 or later in framework mode.

Setup steps

Create a new React app using React Router

If you don't already have a React app using React Router, run the following commands to create a new one⁠.

npm create react-router@latest clerk-react-router
cd clerk-react-router

Install @clerk/react-router

The Clerk React Router SDK gives you access to prebuilt components, hooks, and helpers to make user authentication easier.

Run the following command to install the SDK:

npm install @clerk/react-router

Set your Clerk API keys

If you haven't already, create a new Clerk application in the Clerk Dashboard⁠. For more information, see the setup guide.

  1. In the Clerk Dashboard, navigate to the API keys⁠ page.
  2. In the Quick Copy section, copy your Clerk Publishable Key⁠ and Secret Key⁠.
  3. Paste your keys into your .env file.

The final result should resemble the following:

.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. It also allows you to protect specific routes from unauthenticated users. To add clerkMiddleware() to your app, follow these steps:

Important: If you're using React Router v7, enable the v8_middleware future flag in your react-router.config.ts file.

In your react-router.config.ts file:

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

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

Example of root.tsx file

Add the following code to your root.tsx file:

import { 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)

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>
    )
}

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>
    )
}

Protected routes

By default, clerkMiddleware() will not protect any routes. All routes are public and you must opt-in to protection for routes. See the clerkMiddleware() reference to learn how to require authentication for specific routes.

Add <ClerkProvider> and Clerk components to your app

The 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.

Copy and paste the following code into your root.tsx file. This:

In your root.tsx file:

import { ClerkProvider, SignInButton, SignUpButton, Show, UserButton } from '@clerk/react-router'
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router'
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'

export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]

export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args)

// 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 when="signed-out">
          <SignInButton />
          <SignUpButton />
        </Show>
        <Show when="signed-in">
          <UserButton />
        </Show>
      </header>
      <Outlet />
    </ClerkProvider>
  )
}

This example uses the following components:

- [<Show when="signed-in">](/content/docs/react-router/reference/components/control/show/index.html): Children of this component can only be seen while **signed in**.
- [<Show when="signed-out">](/content/docs/react-router/reference/components/control/show/index.html): Children of this component can only be seen while **signed out**.
- [<UserButton />](/content/docs/react-router/reference/components/user/user-button/index.html): Shows the signed-in user's avatar. Selecting it opens a dropdown menu with account management options.
- [<SignInButton />](/content/docs/react-router/reference/components/unstyled/sign-in-button/index.html): An unstyled component that links to the sign-in page. In this example, since no props or environment variables are set for the sign-in URL, this component links to the [Account Portal sign-in page](/content/docs/guides/account-portal/overview#sign-in/index.html).
- [<SignUpButton />](/content/docs/react-router/reference/components/unstyled/sign-up-button/index.html): An unstyled component that links to the sign-up page. In this example, since no props or environment variables are set for the sign-up URL, this component links to the [Account Portal sign-up page](/content/docs/guides/account-portal/overview#sign-up/index.html).

## Run your project

Run your project with the following command:

```bash
npm run dev

Create your first user

  1. Visit your app's homepage at http://localhost:5173⁠.
  2. Select "Sign up" on the page and authenticate to create your first user.

Next steps

Explore the most relevant next steps for your SDK using the following guides.

Prebuilt components

Learn how to add Clerk's prebuilt authentication and user-management UI to your app.

Build custom flows

Learn how to build custom user interfaces entirely from scratch using the Clerk API.

Read user data

Learn how to use Clerk's helpers to read user data in your app.

Customization & localization

Learn how to customize and localize Clerk components.

More to explore

Explore additional Clerk features that help you build, manage, and grow your application.