Skip to content
Back to skills

Clerk React Router Patterns

ASecurity

'React Router v7 patterns with Clerk — rootAuthLoader, getAuth in loaders,

  • 83 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 11, 2026
toolsreact

Works with

  • cli

Security analysis

A100/100

Pro scans all 11 files and shows the line behind each finding

Scanned June 11, 2026

npx -y skills add clerk/skills --skill clerk-react-router-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Clerk React Router Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Clerk React Router Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/clerk-clerk-react-router-patterns/badge)](https://www.skillsdirectory.com/skills/clerk-clerk-react-router-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: clerk-react-router-patterns
description: 'React Router v7 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.'
license: MIT
allowed-tools: WebFetch
metadata:
  author: clerk
  version: 1.0.0
---

# React Router Patterns

SDK: `@clerk/react-router` v3+. Requires React Router v7.9+.

## 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 |

## Mental Model

React Router v7 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
```

## Minimal Setup

### 1. root.tsx

```tsx
import { rootAuthLoader } from '@clerk/react-router/server'
import { ClerkApp } from '@clerk/react-router'
import type { Route } from './+types/root'

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

export default ClerkApp(function App() {
  return <Outlet />
})
```

### 2. Middleware (root route or entry.server.ts)

```tsx
import { clerkMiddleware } from '@clerk/react-router/server'
export const middleware = [clerkMiddleware()]
```

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

## Auth in Loaders

```tsx
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

```tsx
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

```tsx
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

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

export function Nav() {
  return <OrganizationSwitcher afterSelectOrganizationUrl="/dashboard" />
}
```

```tsx
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 |
|---------|-------|-----|
| `clerkMiddleware() not detected` | Missing middleware | Export `middleware = [clerkMiddleware()]` from root route |
| `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` |
| `ClerkApp` | `@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](https://clerk.com/docs/react-router/getting-started/quickstart)

Files in this skill

  • SKILL.md4.5 KB
  • evals/evals.json4.3 KB
  • references/loaders-actions.md1.7 KB
  • references/protected-routes.md1.7 KB
  • references/ssr-auth.md1.4 KB
  • templates/react-router-basic-auth/app/root.tsx2.4 KB
  • templates/react-router-basic-auth/app/routes.ts132 B
  • templates/react-router-basic-auth/app/routes/home.tsx57 B
  • templates/react-router-basic-auth/package.json425 B
  • templates/react-router-basic-auth/react-router.config.ts134 B
  • templates/react-router-basic-auth/vite.config.ts150 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.