← Files ClerkARCHIVED FILE

skills/clerk-react-router-patterns/references/loaders-actions.md

1.7 KB · Sep 30, 2026 · 23:09 UTC

↓ Download file

# Loaders and Actions Auth

## getAuth in Loaders

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

export async function loader(args: Route.LoaderArgs) {
  const { userId, orgId, sessionId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')
  return { data: await db.query(userId) }
}
```

## getAuth in Actions

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

  const fd = await args.request.formData()
  await db.insert({ userId, title: fd.get('title') })
  return redirect('/dashboard')
}
```

## rootAuthLoader Callback Form

Pass a callback to `rootAuthLoader` when you need auth state in the root route:

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

export async function loader(args: Route.LoaderArgs) {
  return rootAuthLoader(args, async ({ request }) => {
    const { userId } = request.auth
    if (!userId) return { user: null }
    return { user: await db.getUser(userId) }
  })
}
```

## Available Auth Fields

| Field | Type | Description |
|-------|------|-------------|
| `userId` | `string \| null` | Current user ID |
| `sessionId` | `string \| null` | Current session ID |
| `orgId` | `string \| null` | Active org ID |
| `orgRole` | `string \| null` | User's role in active org |
| `has()` | `function` | Check permissions/features |

## CRITICAL

- `getAuth` throws if `clerkMiddleware` is not installed
- `rootAuthLoader` must be called in `root.tsx` loader — not just any loader
- Import `redirect` from `react-router`, not from `@remix-run/react-router`

SHA-256: fa8d7f8e816e8ba94fbbcee2f9f44f1dc51f5648e50d3f5410ec03d0f16d8281