# Clerk on a React SPA (Vite or CRA)

## The env var name is the whole bug

Clerk's React SDK reads the publishable key from the environment at build time, and the variable name depends on the bundler:

- Vite: `VITE_CLERK_PUBLISHABLE_KEY`
- Create React App: `REACT_APP_CLERK_PUBLISHABLE_KEY`

Put the wrong prefix and `import.meta.env.VITE_CLERK_PUBLISHABLE_KEY` is `undefined`. Clerk then errors about a missing publishable key. If you see that error, check the prefix before anything else.

Never put `CLERK_SECRET_KEY` in a SPA. There is no server to hide it in; anything in the client bundle ships to the browser. SPAs only ever get the publishable key.

## Provider placement

Wrap the app at the entry point so every hook has context:

```tsx
import { ClerkProvider } from '@clerk/react'

createRoot(document.getElementById('root')!).render(
  [StrictMode]
    [ClerkProvider]
      [App /]
    [/ClerkProvider]
  [/StrictMode],
)
```

`ClerkProvider` must actually wrap the components that call `useAuth()`, `useUser()`, etc. A provider mounted beside the router instead of around it gives "hook used outside provider" errors.

## Checklist

- After adding the env var, restart the dev server. Vite bakes env vars at startup; editing `.env` mid-session changes nothing until restart.
- Use `@clerk/react`, the current package name. Old tutorials import `@clerk/clerk-react`, which is the legacy Core 2 name.
- Sign-in/sign-up buttons with no configured URLs fall back to Clerk's Account Portal pages. That is fine for a prototype, but set explicit URLs before it confuses users.
- Confirm the key type matches the instance: a `pk_test` key against a production instance (or vice versa) fails auth in ways that look like code bugs.