# Upgrading from v2 to v3

> As of April 4, 2025, RedwoodJS is no longer actively developed. [Learn more](https://community.redwoodjs.com/t/the-future-of-redwood-launches-today/7938).

On March 24, 2022, Clerk launched version 3 of its full suite of JavaScript libraries, including our SDKs for React, Next.js, Remix, and Redwood. This guide helps you with upgrading to the next major version of your SDK.

## Why upgrade?

Version 3 includes a number of bug fixes, developer experience improvements, and altogether new features, including:

- Support for server-side rendering
- Reduced React re-renders
- Improved Typescript types and IntelliSense autocomplete

## Client-side changes (all frameworks)

These changes apply to all frameworks, regardless of which one you use specifically.

### Upgrade dependencies

**Next.js**

filename: terminal
```sh
npm install @clerk/nextjs@latest
```

### `useAuth()` introduction

[useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) is a new, SSR-compatible hook that is recommended for all authentication tasks.

```jsx
const { userId, sessionId, getToken, isLoaded, isSignedIn, signOut } = useAuth()
```

The [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) hook unifies the way you access common auth operations. It replaces:

- `useSession()` to access `getToken()` or the `sessionId`
- `useUser()` to access `getToken()` for integrations
- `useClerk()` to access `signOut()`
- `<SignedIn>` and `<SignedOut>` in a way that requires extra components

### Hook and component API changes

Version 3 changes several APIs for improved consistency and usability.

#### `useUser()` and `useSession()`

Previously, `useUser` and `useSession` could only be called from inside the `<SignedIn>` component. This restriction has been relaxed, but now developers must manually handle the possibility the user and session objects may not be loaded when the hook is called.

In a future version, we plan to support React `<Suspense />` to make this even easier.

| Old API                         | New API                                                                                                                                                                                                    |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `const user = useUser();`       | `const { isLoaded, isSignedIn, user } = useUser();`                                                                                                                                                        |
| `const session = useSession();` | `const { isLoaded, isSignedIn, session } = useSession();` <br />If you only call `useSession` for the ID or `getToken`, switch to [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) instead. |

#### `<RedirectToSignIn />` and `<RedirectToSignUp/>`

The behavior enabled by the `returnBack` prop has now been promoted to default behavior. `returnBack` is deprecated in favor of using an empty component.

| Old API                          | New API                |
| -------------------------------- | ---------------------- |
| `<RedirectToSignIn returnBack/>` | `<RedirectToSignIn />` |
| `<RedirectToSignUp returnBack/>` | `<RedirectToSignUp />` |

#### `<SignIn />` and `<SignUp />`

Props which take URLs (absolute or relative) have been standardized to use the Url (camelCase) suffix.

| Old API       | New API          |
| ------------- | ---------------- |
| `afterSignIn` | `afterSignInUrl` |
| `afterSignUp` | `afterSignUpUrl` |
| `signUpURL`   | `signUpUrl`      |
| `signInURL`   | `signInUrl`      |

#### `<UserButton />`

Props which take URLs (absolute or relative) have been standardized to use the Url (camelCase) suffix.

| Old API              | New API                             |
| -------------------- | ----------------------------------- |
| `afterSwitchSession` | `afterSwitchSessionUrl`             |
| `userProfileURL`     | `userProfileUrl`                    |
| `signInURL`          | `signInUrl`                         |
| `afterSignOutAll`    | `afterSignOutUrl`                   |
| `afterSignOutOne`    | `afterMultiSessionSingleSignOutUrl` |

#### `useSignUp()` & `useSignIn()`

`useSignUp()` and `useSignIn()` are no longer required to be contained in `<SignedOut>` or `<ClerkLoaded>`. Instead, they have been updated to include a loading state.

| Old API                       | New API                                     |
| ----------------------------- | ------------------------------------------- |
| `const signUp = useSignUp();` | `const { isLoaded, signUp } = useSignUp();` |
| `const signIn = useSignIn();` | `const { isLoaded, signIn } = useSignIn();` |

### Resource changes

In order to make our APIs easier to use in codebases not using Typescript and make them more consistent across frameworks, we removed support for snake\_cased method parameters. We also updated all method signatures to always accept a param object instead of plain positional params.

We expect that most users will only need to apply these changes to the `user.update()`, `user.createEmailAddress()` and `user.createPhoneNumber()` methods as shown below.

Users who have built custom auth flows using the SignIn and SignUp resources can consult the [SignUp and SignIn section below](#sign-up-and-sign-in).

#### User

`User.getToken("token-name")` has been deprecated and is now accessible through `getToken` from the `useAuth()` hook or `Session.getToken()`.

The new `getToken()` method accepts an optional `{ template: string; }` object, used to specify the JWT template you want to use.

If you want to fetch a token for an integration, you must prefix the integration name with `integration_`, eg: `getToken({ template: 'integration_firebase' })`.

Moreover, the following methods now accept a params objects instead of positional params: `createEmailAddress()`, `createPhoneNumber()`, `setProfileImage()`.

Respecting the camelCase changes we explained at the start of this section, all method params should now use camelCasing. An example for the create method is shown below.

| Old API                                          | New API                                                                                                                                                         |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `User.getToken("token-name")`                    | `const { getToken } = useAuth();` <br />or `getToken({ template: "integration_token-name" })` <br />or `Session.getToken({template: "integration_token-name"})` |
| `User.createEmailAddress(value)`                 | `User.createEmailAddress({ email: value })`                                                                                                                     |
| `User.createPhoneNumber(value)`                  | `User.createPhoneNumber({ phoneNumber: value })`                                                                                                                |
| `User.setProfileImage(file)`                     | `User.setProfileImage(file)`                                                                                                                                    |
| `User.update({ first_name: "", last_name: "" })` | `User.update({ firstName: "", lastName: "" })`                                                                                                                  |

#### SignUp and SignIn

The `createEmailLinkFlow` and `authenticateWithRedirect` calls have had parameters renamed to use the word "redirect" instead of "callback."

| Old API                                                          | New API                                                          |
| ---------------------------------------------------------------- | ---------------------------------------------------------------- |
| `createEmailLinkFlow({ callbackUrl })`                           | `createEmailLinkFlow({ redirectUrl })`                           |
| `authenticateWithRedirect({ callbackUrl, callbackUrlComplete })` | `authenticateWithRedirect({ redirectUrl, redirectUrlComplete })` |

## Next.js server-side changes

> Before starting this guide, complete the [Client-side changes](#client-side-changes-all-frameworks).

### API routes

Helpers for API routes have been updated to mirror the new [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) hook on the client-side.

- `withSession` is deprecated and replaced with `withAuth`
- `requireSession` is deprecated with replaced with `requireAuth`
- Instead of decorating the `Request` object with a `Session` object, it is now decorated with an `Auth` object that mirrors [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) on the client-side.
  - `const { userId, sessionId, getToken } = req.auth;`

#### Example usage

```jsx
import { withAuth } from '@clerk/nextjs/api'

export default withAuth(async (req, res) => {
  const { userId, sessionId, getToken } = req.auth
  const hasuraToken = await getToken({ template: 'hasura' })
  // Your handler
})
```

### Edge middleware

Edge middleware has also been updated to mirror the new [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) hook on the client-side. The import path has also been changed to avoid confusion.

```jsx
import { withEdgeMiddlewareAuth } from '@clerk/nextjs/edge-middleware'

export const middleware = withEdgeMiddlewareAuth((req, ev) => {
  const { userId, sessionId, getToken } = req.auth
  // Your middleware
})
```

## Express server-side changes

> Before starting this guide, complete the [Client-side changes](#client-side-changes-all-frameworks).

### Middleware

Express middleware been updated to mirror the new [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) hook on the client-side.

- `ClerkExpressWithSession` is deprecated and replaced with `ClerkExpressWithAuth`
- `ClerkExpressRequireSession` is deprecated and replaced with `ClerkExpressRequireAuth`
- Instead of decorating the `Request` object with a `Session` object, it is now decorated with an `Auth` object that mirrors [useAuth()](https://clerk.com/docs/reference/hooks/use-auth.md) on the client-side.
  - `const { userId, sessionId, getToken } = req.auth;`

#### Example usage

```js
import { ClerkExpressRequireAuth } from '@clerk/clerk-sdk-node'

app.use(ClerkExpressRequireAuth())
app.get('/', (req, res) => {
  const { userId, sessionId, getToken } = req.auth
  // Your handler...
})
```

[use-auth]: /docs/reference/hooks/use-auth

---

## Sitemap

[Overview of all docs pages](https://clerk.com/docs/llms.txt)
