Generated banner for Clerk React Router Patterns
Generated logo for Clerk React Router Patterns

Clerk React Router Patterns

ClerkOfficialCreated by clerk

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Low risk
  • Has scripts

From the author

React Router v7/v8 patterns with Clerk — rootAuthLoader, getAuth in loaders, clerkMiddleware, protected routes, SSR user data, org switching. Triggers on: react-router auth, rootAuthLoader, getAuth loader, react-router protected route, loader authentication, SSR auth react-router, useNavigate may be used only in the context of a Router.
— the description by clerk

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides the essential patterns for implementing Clerk authentication within React Router v7 and v8 projects. It covers the necessary middleware setup, root loader configuration, and methods for protecting routes and accessing user session data on both the server and client. It also addresses specific configuration requirements for Vite and React Router version differences to ensure smooth SSR and authentication flow.

What it does

  • Configures clerkMiddleware for request-level authentication handling.
  • Implements rootAuthLoader to inject Clerk state into the application.
  • Provides patterns for protecting routes at the loader level.
  • Enables server-side auth checks using getAuth in loaders and actions.
  • Supports organization switching and role-based access control.
  • Offers client-side hooks like useAuth and useUser for UI components.

When to use it

  • When adding authentication to a new React Router v7 or v8 application.
  • When migrating or upgrading authentication patterns between React Router versions.
  • When implementing server-side route protection to prevent unauthorized access.
  • When needing to access user session or organization data within loaders and actions.

Advantages

  • Ensures secure, server-side authentication before page rendering.
  • Provides clear patterns for both v7 and v8 configuration differences.
  • Offers robust support for complex features like organization switching.
  • Includes troubleshooting steps for common SSR and context-related errors.

Usage examples

“How do I protect a route in my React Router loader?”
You should use the getAuth(args) function inside your loader to check for a userId, throwing a redirect to the sign-in page if the user is not authenticated.
“I am getting a useNavigate context error during SSR in React Router v8, how do I fix it?”
You need to add 'ssr: { noExternal: ['@clerk/react-router'] }' to your vite.config.ts file to resolve module duplication issues.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/clerk/clerk-react-router-patterns/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip clerk-react-router-patterns.zip -d .agents/skills

Documentation by clerk

React Router Patterns

SDK: @clerk/react-router v3.5+. Supports React Router v7.9+ and v8.

What Do You Need?

TaskReference
Auth in loaders and actionsreferences/loaders-actions.md
Protected routes and redirectsreferences/protected-routes.md
SSR user data and sessionreferences/ssr-auth.md

React Router v7 vs v8

Check the installed react-router major version before scaffolding — the config differs:

v7.9+v8+
Middleware APIOpt-in: set future: { v8_middleware: true } in react-router.config.tsAlways on — do NOT set the flag (v8 removed it)
ssr.noExternal workaround (below)Not neededRequired

Minimal Setup

1. vite.config.ts (v8 only — REQUIRED)

React Router v8 ships development/production conditional exports. In react-router dev, Vite externalizes @clerk/react-router for SSR, so Node resolves the production build of react-router while the app code gets the development build — two module instances, two Router contexts. Every request then fails during SSR with:

Error: useNavigate() may be used only in the context of a <Router> component.

npm ls react-router shows a single copy — that does NOT rule this out. The duplication is per export condition, not per installed copy. Do not chase duplicate installs; add the workaround from the upstream React Router issue:

import { reactRouter } from '@react-router/dev/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [reactRouter()],
  ssr: {
    noExternal: ['@clerk/react-router'],
  },
})
2. root.tsx
import { Outlet } from 'react-router'
import { rootAuthLoader, clerkMiddleware } from '@clerk/react-router/server'
import { ClerkProvider } from '@clerk/react-router'
import type { Route } from './+types/root'

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

export async function loader(args: Route.LoaderArgs) {
  return rootAuthLoader(args)
}

export default function App({ loaderData }: Route.ComponentProps) {
  return (
    <ClerkProvider loaderData={loaderData}>
      <Outlet />
    </ClerkProvider>
  )
}

There is no ClerkApp HOC in @clerk/react-router (that was the @clerk/remix API). Render <ClerkProvider loaderData={loaderData}> inside the default export and pass it the root route's loaderData.

3. react-router.config.ts (v7 only)
import type { Config } from '@react-router/dev/config'

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

On v8, omit the future block entirely — the flag no longer exists.

Required: rootAuthLoader must be called in root.tsx's loader. Without it, getAuth throws in nested loaders.

Mental Model

React Router v7/v8 uses a middleware + loader pipeline. Clerk plugs into both layers:

  • Middleware (clerkMiddleware()) — runs on every request, attaches auth to context

  • rootAuthLoader — required in root.tsx to pass Clerk state to the client

  • getAuth(args) — called inside any loader/action to get the current user

Request → clerkMiddleware() → rootAuthLoader → page loader → component
                 ↓                   ↓               ↓
           attaches auth      injects state     getAuth(args)
           to context         to response       reads context

Auth in Loaders

import { getAuth } from '@clerk/react-router/server'
import type { Route } from './+types/dashboard'

export async function loader(args: Route.LoaderArgs) {
  const { userId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')

  const data = await fetchUserData(userId)
  return { data }
}

Auth in Actions

import { getAuth } from '@clerk/react-router/server'

export async function action(args: Route.ActionArgs) {
  const { userId, orgId } = await getAuth(args)
  if (!userId) throw new Response('Unauthorized', { status: 401 })

  const formData = await args.request.formData()
  await saveData(userId, orgId, formData)
  return redirect('/dashboard')
}

Client Components

import { useAuth, useUser } from '@clerk/react-router'

export function Profile() {
  const { userId, isSignedIn } = useAuth()
  const { user } = useUser()
  if (!isSignedIn) return null
  return <p>{user?.firstName}</p>
}

Org Switching

import { OrganizationSwitcher } from '@clerk/react-router'

export function Nav() {
  return <OrganizationSwitcher afterSelectOrganizationUrl="/dashboard" />
}
export async function loader(args: Route.LoaderArgs) {
  const { userId, orgId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')
  if (!orgId) throw redirect('/select-org')

  return { data: await fetchOrgData(orgId) }
}

Common Pitfalls

SymptomCauseFix
useNavigate() may be used only in the context of a <Router> thrown from ClerkProvider during SSR in dev (v8)Vite dev SSR externalizes @clerk/react-router, which then loads react-router's production build while the app uses the development build — two Router contexts. A single copy in npm ls does not rule this out.Add ssr: { noExternal: ['@clerk/react-router'] } to vite.config.ts. Do NOT downgrade to v7
Build error: ClerkApp is not exportedClerkApp does not exist in @clerk/react-routerUse <ClerkProvider loaderData={loaderData}> in root.tsx's default export
clerkMiddleware() not detectedMissing middleware (or on v7, missing v8_middleware future flag)Export middleware = [clerkMiddleware()] from root route; on v7 also set future: { v8_middleware: true }
Unknown future flag error/warning (v8)v8_middleware flag left in react-router.config.ts after upgradingRemove the future.v8_middleware entry — middleware is always on in v8
getAuth returns empty userIdrootAuthLoader not calledCall rootAuthLoader(args) in root.tsx loader
Infinite redirect loopRedirect target is also protectedExclude /sign-in from protection check
redirect not working in actionUsing Response instead of throw redirect()Use throw redirect('/path') from react-router

Import Map

WhatImport From
getAuth@clerk/react-router/server
rootAuthLoader@clerk/react-router/server
clerkMiddleware@clerk/react-router/server
ClerkProvider@clerk/react-router
useAuth, useUser@clerk/react-router
OrganizationSwitcher@clerk/react-router

See Also

  • clerk-setup - Initial Clerk install

  • clerk-custom-ui - Custom flows & appearance

  • clerk-orgs - B2B organizations

Docs

React Router SDK

Files

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Needs Node.js

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
clerk
Publisher
Clerk (Official)
Source
clerk/skills · skills/clerk-react-router-patterns · commit c5d2c0d
Licence
MIT License (redistribution allowed)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by clerk or Clerk.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download clerk-react-router-patterns.zip