Skip to main content

TanStack React Start 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 to TanStack React Start
# Add Clerk Authentication

Set up Clerk authentication with the Clerk CLI. When the framework supports it, `npx clerk@latest init` defaults to auto-generated temporary development keys that a later `clerk auth login` claims automatically.

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

## Step 1a: Existing project

From the project root:

```bash
npx 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:

```bash
npx 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: Development keys

If the framework supports temporary development keys, `init` writes them to the project's env file, so the user needs no Clerk account. The CLI prints a confirmation naming the env file it wrote, followed by:

```
When you're ready, run clerk auth login and your app will be claimed automatically.
```

Relay that, using the filename the CLI printed: the app stays unclaimed until the user runs `npx clerk@latest auth login`. Do not run it for them unless they ask to claim now.

Frameworks without development-key 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 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 (App and Pages Router), React, React Router, Nuxt, TanStack Start, Astro, Vue, JavaScript/Vite, Expo, Express, Fastify, iOS, and Android.

- `next`: https://clerk.com/docs/nextjs/getting-started/quickstart.md?manual=1
- `astro`: https://clerk.com/docs/astro/getting-started/quickstart.md?manual=1
- `nuxt`: https://clerk.com/docs/nuxt/getting-started/quickstart.md?manual=1
- `react-router`: https://clerk.com/docs/react-router/getting-started/quickstart.md?manual=1
- `@tanstack/react-start`: https://clerk.com/docs/tanstack-react-start/getting-started/quickstart.md?manual=1
- `react`: https://clerk.com/docs/react/getting-started/quickstart.md?manual=1
- `vue`: https://clerk.com/docs/vue/getting-started/quickstart.md?manual=1
- `vite` or vanilla JS: https://clerk.com/docs/js-frontend/getting-started/quickstart
- `express`: https://clerk.com/docs/expressjs/getting-started/quickstart
- `fastify`: https://clerk.com/docs/fastify/getting-started/quickstart
- `expo`: https://clerk.com/docs/expo/getting-started/quickstart
- iOS (Swift): https://clerk.com/docs/ios/getting-started/quickstart
- Android (Kotlin): https://clerk.com/docs/android/getting-started/quickstart
- Chrome Extension: https://clerk.com/docs/chrome-extension/getting-started/quickstart

Everything else: https://clerk.com/docs/llms.txt

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

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

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

Astro imports from `@clerk/astro/components`. Nuxt auto-imports the components; explicit imports come from `@clerk/nuxt/components`. Other frameworks use the same names from their Clerk package, such as `@clerk/vue` or `@clerk/react`.

## Step 4: Verify

```bash
npx 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:

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

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

Add to global CSS:

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

## Critical rules

- Next.js 15+: `auth()` is async. Always `await auth()`
- `ClerkProvider` goes inside `<body>`, not wrapping `<html>`
- Never expose `CLERK_SECRET_KEY` in client code
- Use `@clerk/nextjs`, not `@clerk/clerk-react`
- Do not read or print existing environment variable files; ask the user for any missing non-sensitive configuration

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.

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

If yes:

1. Run `npx 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/).

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

Step-by-step setup instructions

Create a new TanStack React Start app

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

npm create @tanstack/start@latest clerk-tanstack-react-start
cd clerk-tanstack-react-start
pnpm create @tanstack/start clerk-tanstack-react-start
cd clerk-tanstack-react-start
yarn create @tanstack/start clerk-tanstack-react-start
cd clerk-tanstack-react-start
bunx @tanstack/create-start@latest clerk-tanstack-react-start
cd clerk-tanstack-react-start

Install @clerk/tanstack-react-start

The Clerk TanStack React Start SDKTanstack Start Icon gives you access to prebuilt components, hooks, and helpers to make user authentication easier.

Run the following command to install the SDK:

terminal
npm install @clerk/tanstack-react-start
terminal
pnpm add @clerk/tanstack-react-start
terminal
yarn add @clerk/tanstack-react-start
terminal
bun add @clerk/tanstack-react-start
.env
VITE_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
CLERK_SECRET_KEY=YOUR_SECRET_KEY

Add clerkMiddleware() to your app

clerkMiddleware()Tanstack Start Icon 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:

  1. Create a src/start.ts file with the following code:

    src/start.ts
    import { clerkMiddleware } from '@clerk/tanstack-react-start/server'
    import { createStart } from '@tanstack/react-start'
    
    export const startInstance = createStart(() => {
      return {
        requestMiddleware: [clerkMiddleware()],
      }
    })
  2. By default, clerkMiddleware() will not protect any routes. All routes are public and you must opt-in to protection for routes. See the clerkMiddleware() referenceTanstack Start Icon to learn how to require authentication for specific routes.

Add <ClerkProvider> to your app

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

Add the <ClerkProvider> component to your app's root route, as shown in the following example:

src/routes/__root.tsx
import { ClerkProvider } from '@clerk/tanstack-react-start'
30 lines collapsedimport { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import appCss from '../styles.css?url' export const Route = createRootRoute({ head: () => ({ meta: [ { charSet: 'utf-8', }, { name: 'viewport', content: 'width=device-width, initial-scale=1', }, { title: 'TanStack Start Starter', }, ], links: [ { rel: 'stylesheet', href: appCss, }, ], }), shellComponent: RootDocument, })
function RootDocument({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <HeadContent /> </head> <body> <ClerkProvider>{children}</ClerkProvider> <TanStackRouterDevtools /> <Scripts /> </body> </html> ) }

Protect your pages

Client-side

To protect your pages on the client-side, you can use Clerk's prebuilt control components that control the visibility of content based on the user's authentication state.

The following example uses the following components:

src/routes/index.tsx
import { UserButton, Show, SignInButton, SignUpButton } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/')({
  component: Home,
})

function Home() {
  return (
    <div>
      <h1>Index Route</h1>
      <Show when="signed-in">
        <UserButton />
      </Show>
      <Show when="signed-out">
        <SignInButton />
        <SignUpButton />
      </Show>
    </div>
  )
}

Server-side

To protect your routes, create a server function that checks the user's authentication state via the auth()Tanstack Start Icon method. If the user is not authenticated, they are redirected to a sign-in page. If authenticated, the user's userId is passed to the route, allowing access to the <Home /> component, which welcomes the user and displays their userId. The beforeLoad() method ensures authentication is checked before loading the page, and the loader() method returns the user data for use in the component.

Tip

Ensure that your app has the TanStack Start server handler configured in order for your server routes to work.

src/routes/index.tsx
import { createFileRoute, redirect } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
import { auth } from '@clerk/tanstack-react-start/server'

const authStateFn = createServerFn().handler(async () => {
  const { isAuthenticated, userId } = await auth()

  if (!isAuthenticated) {
    // This will error because you're redirecting to a path that doesn't exist yet
    // You can create a sign-in route to handle this
    // See https://clerk.com/docs/tanstack-react-start/guides/development/custom-sign-in-or-up-page
    throw redirect({
      to: '/sign-in',
    })
  }

  return { userId }
})

export const Route = createFileRoute('/')({
  component: Home,
  beforeLoad: async () => await authStateFn(),
  loader: async ({ context }) => {
    return { userId: context.userId }
  },
})

function Home() {
  const state = Route.useLoaderData()

  return <h1>Welcome! Your ID is {state.userId}!</h1>
}

Run your project

Run your project with the following command:

npm run dev
pnpm run dev
yarn dev
bun run dev

Create your first user

  1. Visit your app's homepage at http://localhost:3000.
  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.

  • Organizations - Organizations are shared accounts that let teams collaborate, manage members and roles, and control access to shared resources.
  • Billing - Billing enables you to manage subscriptions, free trials, payments, plans, and billing-related webhook events for B2C and B2B applications.
  • Waitlist - Waitlist lets you collect signups and control access to new products or features before launch through a simple, integrated workflow.

Feedback

What did you think of this content?

Last updated on