mcpbeat Sign in

Clerk React Router Patterns Agent Skill

React Router v7/v8 patterns with Clerk — rootAuthLoader, getAuth in loaders, 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.'

5k tokens
context cost
the whole folder, loaded on every use
12
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
66
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/clerk/skills --skill clerk-react-router-patterns

What comes with it

13 397 bytes besides the instruction
evals/evals.json
references/loaders-actions.md
references/protected-routes.md
references/ssr-auth.md
templates/react-router-basic-auth/app/app.css
templates/react-router-basic-auth/app/root.tsx
templates/react-router-basic-auth/app/routes.ts
templates/react-router-basic-auth/app/routes/home.tsx
templates/react-router-basic-auth/package.json
templates/react-router-basic-auth/react-router.config.ts
templates/react-router-basic-auth/vite.config.ts

What it tells the agent to use

found in the instruction text
WebFetch fetches pages from the network

The instruction itself

16 sections, as written by the author

React Router Patterns

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

What Do You Need?

| Task | Reference |

|------|-----------|

| Auth in loaders and actions | references/loaders-actions.md |

| Protected routes and redirects | references/protected-routes.md |

| SSR user data and session | references/ssr-auth.md |

React Router v7 vs v8

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

| | v7.9+ | v8+ |

|--|--|--|

| Middleware API | Opt-in: set future: { v8_middleware: true } in react-router.config.ts | Always on — do NOT set the flag (v8 removed it) |

| ssr.noExternal workaround (below) | Not needed | Required |

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 (upstream issue:

https://github.com/remix-run/react-router/issues/15232):

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

| Symptom | Cause | Fix |

|---------|-------|-----|

| 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 exported | ClerkApp does not exist in @clerk/react-router | Use <ClerkProvider loaderData={loaderData}> in root.tsx's default export |

| clerkMiddleware() not detected | Missing 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 upgrading | Remove the future.v8_middleware entry — middleware is always on in v8 |

| getAuth returns empty userId | rootAuthLoader not called | Call rootAuthLoader(args) in root.tsx loader |

| Infinite redirect loop | Redirect target is also protected | Exclude /sign-in from protection check |

| redirect not working in action | Using Response instead of throw redirect() | Use throw redirect('/path') from react-router |

Import Map

| What | Import 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

Other skills for the same job

different authors, same section of the catalogue
MCP Builder
by anthropics
vendor ×13

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

30k tokens scripts
Changelog Generator
by frostant
×9

Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.

774 tokens
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
MCP Builder
by JayZeeDesign
×7

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

37k tokens scripts
Vercel React Native Skills
by vercel-labs
vendor ×6

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

39k tokens
Vercel React Best Practices
by ratacat
×5

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

34k tokens
Next Best Practices
by vercel-labs
vendor ×4

Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

20k tokens
Using Git Worktrees
by ZhanlinCui
×4

Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification

1k tokens

How to use it

Copy the folder

Take clerk/clerk-react-router-patterns from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.