Repository: clerk/javascript
Pull request #5533: feat(nextjs): Support `auth().redirectToSignUp()`
Author: login: panteliselef
Labels: name: nextjs
name: backend
Created: 2025-04-04T11:06:23Z | Merged: 2025-04-07T11:02:48Z

## Description

[Original PR](https://github.com/clerk/javascript/pull/5407). 

This PR simply removes duplicated code and improves the changeset example.

<!-- 
  Thanks for contributing to Clerk. Make sure to read the contributing guide at https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md before opening a PR!

  **Please create a feature request before starting work on any significant change.**

  Write a brief description of the changes introduced in this PR.
  Include screenshots/videos if they help convey the change.

  Also explain how one can test the change.
-->

<!-- Fixes #(issue number) -->

## Checklist

- [ ] `pnpm test` runs as expected.
- [ ] `pnpm build` runs as expected.
- [ ] (If applicable) [JSDoc comments](https://jsdoc.app/about-getting-started.html) have been added or updated for any package exports
- [ ] (If applicable) [Documentation](https://github.com/clerk/clerk-docs) has been updated

## Type of change

- [ ] 🐛 Bug fix
- [ ] 🌟 New feature
- [ ] 🔨 Breaking change
- [ ] 📖 Refactoring / dependency upgrade / documentation
- [ ] other:



Diff:
diff --git a/.changeset/spicy-lizards-take.md b/.changeset/spicy-lizards-take.md
new file mode 100644
index 00000000000..096e5cb4731
--- /dev/null
+++ b/.changeset/spicy-lizards-take.md
@@ -0,0 +1,17 @@
+---
+'@clerk/nextjs': minor
+---
+
+- Introduce `auth().redirectToSignUp()` that can be used in API routes and pages. Originally effort by [@sambarnes](https://github.com/clerk/javascript/pull/5407)
+
+```ts
+import { clerkMiddleware } from '@clerk/nextjs/server';
+
+export default clerkMiddleware(async (auth) => {
+  const { userId, redirectToSignUp } = await auth();
+
+  if (!userId) {
+    return redirectToSignUp();
+  }
+});
+```
diff --git a/packages/backend/src/createRedirect.ts b/packages/backend/src/createRedirect.ts
index ee97a00de82..90dd4ae5475 100644
--- a/packages/backend/src/createRedirect.ts
+++ b/packages/backend/src/createRedirect.ts
@@ -97,7 +97,18 @@ export const createRedirect: CreateRedirect = params => {
     }
 
     const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;
-    const targetUrl = signUpUrl || accountsSignUpUrl;
+
+    // Allows redirection to SignInOrUp path
+    function buildSignUpUrl(signIn: string | URL | undefined) {
+      if (!signIn) {
+        return;
+      }
+      const url = new URL(signIn, baseUrl);
+      url.pathname = `${url.pathname}/create`;
+      return url.toString();
+    }
+
+    const targetUrl = signUpUrl || buildSignUpUrl(signInUrl) || accountsSignUpUrl;
 
     if (hasPendingStatus) {
       return redirectToTasks(targetUrl, { returnBackUrl });
diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts
index 1fa1859b3ea..a6a4c39a632 100644
--- a/packages/nextjs/src/app-router/server/auth.ts
+++ b/packages/nextjs/src/app-router/server/auth.ts
@@ -25,6 +25,16 @@ type Auth = AuthObject & {
    * `auth()` on the server-side can only access redirect URLs defined via [environment variables](https://clerk.com/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) or [`clerkMiddleware` dynamic keys](https://clerk.com/docs/references/nextjs/clerk-middleware#dynamic-keys).
    */
   redirectToSignIn: RedirectFun<ReturnType<typeof redirect>>;
+
+  /**
+   * The `auth()` helper returns the `redirectToSignUp()` method, which you can use to redirect the user to the sign-up page.
+   *
+   * @param [returnBackUrl] {string | URL} - The URL to redirect the user back to after they sign up.
+   *
+   * @note
+   * `auth()` on the server-side can only access redirect URLs defined via [environment variables](https://clerk.com/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) or [`clerkMiddleware` dynamic keys](https://clerk.com/docs/references/nextjs/clerk-middleware#dynamic-keys).
+   */
+  redirectToSignUp: RedirectFun<ReturnType<typeof redirect>>;
 };
 
 export interface AuthFn {
@@ -83,7 +93,8 @@ export const auth: AuthFn = async () => {
 
   const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl');
 
-  const redirectToSignIn: RedirectFun<never> = (opts = {}) => {
+  const createRedirectForRequest = (...args: Parameters<RedirectFun<never>>) => {
+    const { returnBackUrl } = args[0] || {};
     const clerkRequest = createClerkRequest(request);
     const devBrowserToken =
       clerkRequest.clerkUrl.searchParams.get(constants.QueryParameters.DevBrowser) ||
@@ -91,21 +102,35 @@ export const auth: AuthFn = async () => {
 
     const encryptedRequestData = getHeader(request, constants.Headers.ClerkRequestData);
     const decryptedRequestData = decryptClerkRequestData(encryptedRequestData);
+    return [
+      createRedirect({
+        redirectAdapter: redirect,
+        devBrowserToken: devBrowserToken,
+        baseUrl: clerkRequest.clerkUrl.toString(),
+        publishableKey: decryptedRequestData.publishableKey || PUBLISHABLE_KEY,
+        signInUrl: decryptedRequestData.signInUrl || SIGN_IN_URL,
+        signUpUrl: decryptedRequestData.signUpUrl || SIGN_UP_URL,
+        sessionStatus: authObject.sessionStatus,
+      }),
+      returnBackUrl === null ? '' : returnBackUrl || clerkUrl?.toString(),
+    ] as const;
+  };
+
+  const redirectToSignIn: RedirectFun<never> = (opts = {}) => {
+    const [r, returnBackUrl] = createRedirectForRequest(opts);
+    return r.redirectToSignIn({
+      returnBackUrl,
+    });
+  };
 
-    return createRedirect({
-      redirectAdapter: redirect,
-      devBrowserToken: devBrowserToken,
-      baseUrl: clerkRequest.clerkUrl.toString(),
-      publishableKey: decryptedRequestData.publishableKey || PUBLISHABLE_KEY,
-      signInUrl: decryptedRequestData.signInUrl || SIGN_IN_URL,
-      signUpUrl: decryptedRequestData.signUpUrl || SIGN_UP_URL,
-      sessionStatus: authObject.sessionStatus,
-    }).redirectToSignIn({
-      returnBackUrl: opts.returnBackUrl === null ? '' : opts.returnBackUrl || clerkUrl?.toString(),
+  const redirectToSignUp: RedirectFun<never> = (opts = {}) => {
+    const [r, returnBackUrl] = createRedirectForRequest(opts);
+    return r.redirectToSignUp({
+      returnBackUrl,
     });
   };
 
-  return Object.assign(authObject, { redirectToSignIn });
+  return Object.assign(authObject, { redirectToSignIn, redirectToSignUp });
 };
 
 auth.protect = async (...args: any[]) => {
diff --git a/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts b/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts
index 253f4772f5d..11c0fe1a3a1 100644
--- a/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts
+++ b/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts
@@ -12,6 +12,8 @@ import { clerkMiddleware } from '../clerkMiddleware';
 import { createRouteMatcher } from '../routeMatcher';
 import { decryptClerkRequestData } from '../utils';
 
+vi.mock('../clerkClient');
+
 const publishableKey = 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA';
 const authenticateRequestMock = vi.fn().mockResolvedValue({
   toAuth: () => ({
@@ -21,15 +23,6 @@ const authenticateRequestMock = vi.fn().mockResolvedValue({
   publishableKey,
 });
 
-vi.mock('../clerkClient', () => {
-  return {
-    clerkClient: () => ({
-      authenticateRequest: authenticateRequestMock,
-      telemetry: { record: vi.fn() },
-    }),
-  };
-});
-
 /**
  * Disable console warnings about config matchers
  */
@@ -45,6 +38,14 @@ afterAll(() => {
   global.console.log = consoleLog;
 });
 
+beforeEach(() => {
+  vi.mocked(clerkClient).mockResolvedValue({
+    authenticateRequest: authenticateRequestMock,
+    // @ts-expect-error - mock
+    telemetry: { record: vi.fn() },
+  });
+});
+
 // Removing this mock will cause the clerkMiddleware tests to fail due to missing publishable key
 // This mock SHOULD exist before the imports
 vi.mock(import('../constants.js'), async importOriginal => {
@@ -301,8 +302,19 @@ describe('clerkMiddleware(params)', () => {
     });
   });
 
-  describe('auth().redirectToSignIn()', () => {
-    it('redirects to sign-in url when redirectToSignIn is called and the request is a page request', async () => {
+  describe.each([
+    {
+      name: 'auth().redirectToSignIn()',
+      util: 'redirectToSignIn',
+      locationHeader: 'sign-in',
+    } as const,
+    {
+      name: 'auth().redirectToSignUp()',
+      util: 'redirectToSignUp',
+      locationHeader: 'sign-up',
+    } as const,
+  ])('$name', ({ util, locationHeader }) => {
+    it(`redirects to ${locationHeader} url when ${util} is called and the request is a page request`, async () => {
       const req = mockRequest({
         url: '/protected',
         headers: new Headers({ [constants.Headers.SecFetchDest]: 'document' }),
@@ -310,16 +322,15 @@ describe('clerkMiddleware(params)', () => {
       });
 
       const resp = await clerkMiddleware(async auth => {
-        const { redirectToSignIn } = await auth();
-        redirectToSignIn();
+        (await auth())[util]();
       })(req, {} as NextFetchEvent);
 
       expect(resp?.status).toEqual(307);
-      expect(resp?.headers.get('location')).toContain('sign-in');
+      expect(resp?.headers.get('location')).toContain(locationHeader);
       expect((await clerkClient()).authenticateRequest).toBeCalled();
     });
 
-    it('redirects to sign-in url when redirectToSignIn is called with the correct returnBackUrl', async () => {
+    it(`redirects to ${locationHeader} url when redirectToSignIn is called with the correct returnBackUrl`, async () => {
       const req = mockRequest({
         url: '/protected',
         headers: new Headers({ [constants.Headers.SecFetchDest]: 'document' }),
@@ -327,18 +338,16 @@ describe('clerkMiddleware(params)', () => {
       });
 
       const resp = await clerkMiddleware(async auth => {
-        const { redirectToSignIn } = await auth();
-        redirectToSignIn();
+        (await auth())[util]();
       })(req, {} as NextFetchEvent);
 
-      expect(resp?.status).toEqual(307);
       expect(resp?.status).toEqual(307);
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       expect(new URL(resp!.headers.get('location')!).searchParams.get('redirect_url')).toContain('/protected');
       expect((await clerkClient()).authenticateRequest).toBeCalled();
     });
 
-    it('redirects to sign-in url with redirect_url set to the  provided returnBackUrl param', async () => {
+    it(`redirects to ${locationHeader} url with redirect_url set to the provided returnBackUrl param`, async () => {
       const req = mockRequest({
         url: '/protected',
         headers: new Headers({ [constants.Headers.SecFetchDest]: 'document' }),
@@ -346,12 +355,11 @@ describe('clerkMiddleware(params)', () => {
       });
 
       const resp = await clerkMiddleware(async auth => {
-        const { redirectToSignIn } = await auth();
-        redirectToSignIn({ returnBackUrl: 'https://www.clerk.com/hello' });
+        (await auth())[util]({ returnBackUrl: 'https://www.clerk.com/hello' });
       })(req, {} as NextFetchEvent);
 
       expect(resp?.status).toEqual(307);
-      expect(resp?.headers.get('location')).toContain('sign-in');
+      expect(resp?.headers.get('location')).toContain(locationHeader);
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       expect(new URL(resp!.headers.get('location')!).searchParams.get('redirect_url')).toEqual(
         'https://www.clerk.com/hello',
@@ -359,7 +367,7 @@ describe('clerkMiddleware(params)', () => {
       expect((await clerkClient()).authenticateRequest).toBeCalled();
     });
 
-    it('redirects to sign-in url without a redirect_url when returnBackUrl is null', async () => {
+    it(`redirects to ${locationHeader} url without a redirect_url when returnBackUrl is null`, async () => {
       const req = mockRequest({
         url: '/protected',
         headers: new Headers({ [constants.Headers.SecFetchDest]: 'document' }),
@@ -367,18 +375,48 @@ describe('clerkMiddleware(params)', () => {
       });
 
       const resp = await clerkMiddleware(async auth => {
-        const { redirectToSignIn } = await auth();
-        redirectToSignIn({ returnBackUrl: null });
+        (await auth())[util]({ returnBackUrl: null });
       })(req, {} as NextFetchEvent);
 
       expect(resp?.status).toEqual(307);
-      expect(resp?.headers.get('location')).toContain('sign-in');
+      expect(resp?.headers.get('location')).toContain(locationHeader);
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       expect(new URL(resp!.headers.get('location')!).searchParams.get('redirect_url')).toBeNull();
       expect((await clerkClient()).authenticateRequest).toBeCalled();
     });
   });
 
+  describe('auth().redirectToSignUp()', () => {
+    it('to support signInOrUp', async () => {
+      vi.mocked(clerkClient).mockResolvedValue({
+        authenticateRequest: vi.fn().mockResolvedValue({
+          toAuth: () => ({
+            debug: (d: any) => d,
+          }),
+          headers: new Headers(),
+          publishableKey,
+          signInUrl: '/hello',
+        }),
+        // @ts-expect-error - mock
+        telemetry: { record: vi.fn() },
+      });
+
+      const req = mockRequest({
+        url: '/protected',
+        headers: new Headers({ [constants.Headers.SecFetchDest]: 'document' }),
+        appendDevBrowserCookie: true,
+      });
+
+      const resp = await clerkMiddleware(async auth => {
+        (await auth()).redirectToSignUp();
+      })(req, {} as NextFetchEvent);
+
+      expect(resp?.status).toEqual(307);
+      expect(resp?.headers.get('location')).toContain(`/hello/create`);
+      expect((await clerkClient()).authenticateRequest).toBeCalled();
+    });
+  });
+
   describe('auth.protect()', () => {
     it('redirects to sign-in url when protect is called, the user is signed out and the request is a page request', async () => {
       const req = mockRequest({
diff --git a/packages/nextjs/src/server/clerkMiddleware.ts b/packages/nextjs/src/server/clerkMiddleware.ts
index 9b093db3802..929eaf3c3e9 100644
--- a/packages/nextjs/src/server/clerkMiddleware.ts
+++ b/packages/nextjs/src/server/clerkMiddleware.ts
@@ -17,8 +17,10 @@ import {
   isNextjsNotFoundError,
   isNextjsRedirectError,
   isRedirectToSignInError,
+  isRedirectToSignUpError,
   nextjsRedirectError,
   redirectToSignInError,
+  redirectToSignUpError,
 } from './nextErrors';
 import type { AuthProtect } from './protect';
 import { createProtect } from './protect';
@@ -33,6 +35,7 @@ import {
 
 export type ClerkMiddlewareAuthObject = AuthObject & {
   redirectToSignIn: RedirectFun<Response>;
+  redirectToSignUp: RedirectFun<Response>;
 };
 
 export interface ClerkMiddlewareAuth {
@@ -162,9 +165,13 @@ export const clerkMiddleware = ((...args: unknown[]): NextMiddleware | NextMiddl
       logger.debug('auth', () => ({ auth: authObject, debug: authObject.debug() }));
 
       const redirectToSignIn = createMiddlewareRedirectToSignIn(clerkRequest);
+      const redirectToSignUp = createMiddlewareRedirectToSignUp(clerkRequest);
       const protect = await createMiddlewareProtect(clerkRequest, authObject, redirectToSignIn);
 
-      const authObjWithMethods: ClerkMiddlewareAuthObject = Object.assign(authObject, { redirectToSignIn });
+      const authObjWithMethods: ClerkMiddlewareAuthObject = Object.assign(authObject, {
+        redirectToSignIn,
+        redirectToSignUp,
+      });
       const authHandler = () => Promise.resolve(authObjWithMethods);
       authHandler.protect = protect;
 
@@ -303,6 +310,15 @@ const createMiddlewareRedirectToSignIn = (
   };
 };
 
+const createMiddlewareRedirectToSignUp = (
+  clerkRequest: ClerkRequest,
+): ClerkMiddlewareAuthObject['redirectToSignUp'] => {
+  return (opts = {}) => {
+    const url = clerkRequest.clerkUrl.toString();
+    redirectToSignUpError(url, opts.returnBackUrl);
+  };
+};
+
 const createMiddlewareProtect = (
   clerkRequest: ClerkRequest,
   authObject: AuthObject,
@@ -345,15 +361,21 @@ const handleControlFlowErrors = (
     );
   }
 
-  if (isRedirectToSignInError(e)) {
-    return createRedirect({
+  const isRedirectToSignIn = isRedirectToSignInError(e);
+  const isRedirectToSignUp = isRedirectToSignUpError(e);
+
+  if (isRedirectToSignIn || isRedirectToSignUp) {
+    const redirect = createRedirect({
       redirectAdapter,
       baseUrl: clerkRequest.clerkUrl,
       signInUrl: requestState.signInUrl,
       signUpUrl: requestState.signUpUrl,
       publishableKey: requestState.publishableKey,
       sessionStatus: requestState.toAuth()?.sessionStatus,
-    }).redirectToSignIn({ returnBackUrl: e.returnBackUrl });
+    });
+
+    const { returnBackUrl } = e;
+    return redirect[isRedirectToSignIn ? 'redirectToSignIn' : 'redirectToSignUp']({ returnBackUrl });
   }
 
   if (isNextjsRedirectError(e)) {
diff --git a/packages/nextjs/src/server/nextErrors.ts b/packages/nextjs/src/server/nextErrors.ts
index 034132c17db..d5277a7104f 100644
--- a/packages/nextjs/src/server/nextErrors.ts
+++ b/packages/nextjs/src/server/nextErrors.ts
@@ -4,6 +4,7 @@
 const CONTROL_FLOW_ERROR = {
   REDIRECT_TO_URL: 'CLERK_PROTECT_REDIRECT_TO_URL',
   REDIRECT_TO_SIGN_IN: 'CLERK_PROTECT_REDIRECT_TO_SIGN_IN',
+  REDIRECT_TO_SIGN_UP: 'CLERK_PROTECT_REDIRECT_TO_SIGN_UP',
 };
 
 /**
@@ -92,10 +93,21 @@ function nextjsRedirectError(
   throw error;
 }
 
+function buildReturnBackUrl(url: string, returnBackUrl?: string | URL | null): string | URL {
+  return returnBackUrl === null ? '' : returnBackUrl || url;
+}
+
 function redirectToSignInError(url: string, returnBackUrl?: string | URL | null): never {
   nextjsRedirectError(url, {
     clerk_digest: CONTROL_FLOW_ERROR.REDIRECT_TO_SIGN_IN,
-    returnBackUrl: returnBackUrl === null ? '' : returnBackUrl || url,
+    returnBackUrl: buildReturnBackUrl(url, returnBackUrl),
+  });
+}
+
+function redirectToSignUpError(url: string, returnBackUrl?: string | URL | null): never {
+  nextjsRedirectError(url, {
+    clerk_digest: CONTROL_FLOW_ERROR.REDIRECT_TO_SIGN_UP,
+    returnBackUrl: buildReturnBackUrl(url, returnBackUrl),
   });
 }
 
@@ -135,11 +147,21 @@ function isRedirectToSignInError(error: unknown): error is RedirectError<{ retur
   return false;
 }
 
+function isRedirectToSignUpError(error: unknown): error is RedirectError<{ returnBackUrl: string | URL }> {
+  if (isNextjsRedirectError(error) && 'clerk_digest' in error) {
+    return error.clerk_digest === CONTROL_FLOW_ERROR.REDIRECT_TO_SIGN_UP;
+  }
+
+  return false;
+}
+
 export {
   isNextjsNotFoundError,
   isLegacyNextjsNotFoundError,
   redirectToSignInError,
+  redirectToSignUpError,
   nextjsRedirectError,
   isNextjsRedirectError,
   isRedirectToSignInError,
+  isRedirectToSignUpError,
 };


Reviews:
user: login: LauraBeatris
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T19:47:33Z
user: login: LauraBeatris
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T19:49:23Z
user: login: panteliselef
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T20:32:07Z
user: login: anagstef
body: LGTM
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-07T07:17:49Z
user: login: octoper
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-07T07:48:16Z

Review comments:
diff_hunk: @@ -301,84 +302,121 @@ describe('clerkMiddleware(params)', () => {
     });
   });
 
-  describe('auth().redirectToSignIn()', () => {
-    it('redirects to sign-in url when redirectToSignIn is called and the request is a page request', async () => {
+  describe.each([
+    {
+      name: 'auth().redirectToSignIn()',
+      util: 'redirectToSignIn',
+      locationHeader: 'sign-in',
+    } as const,
+    {
+      name: 'auth().redirectToSignUp()',
+      util: 'redirectToSignUp',
+      locationHeader: 'sign-up',
+    } as const,
+  ])('$name', ({ util, locationHeader }) => {
+    it(`redirects to ${locationHeader} url when redirectToSignIn is called and the request is a page request`, async () => {
path: packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts
user: login: LauraBeatris
body: I think the same applies to the other test cases below

```suggestion
    it(`redirects to ${locationHeader} url when ${util} is called and the request is a page request`, async () => {
```
created_at: 2025-04-04T19:46:30Z
author_association: MEMBER
diff_hunk: @@ -97,7 +97,18 @@ export const createRedirect: CreateRedirect = params => {
     }
 
     const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;
-    const targetUrl = signUpUrl || accountsSignUpUrl;
+
+    // Allows redirection to SignInOrUp path
+    function buildSignUpUrl(signIn: string | URL | undefined) {
path: packages/backend/src/createRedirect.ts
user: login: LauraBeatris
body: Just want to make sure that I understand this part here. If there's a sign in URL option (env var or middleware key), we assume that combined flow is enabled - but doesn't it also need be able via the `withSignUp` prop?
created_at: 2025-04-04T19:49:22Z
author_association: MEMBER
diff_hunk: @@ -97,7 +97,18 @@ export const createRedirect: CreateRedirect = params => {
     }
 
     const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;
-    const targetUrl = signUpUrl || accountsSignUpUrl;
+
+    // Allows redirection to SignInOrUp path
+    function buildSignUpUrl(signIn: string | URL | undefined) {
path: packages/backend/src/createRedirect.ts
user: login: panteliselef
body: yes, but in that case signUpUrl will be defined. `withSignUp` is per component, nothing in can do about it on the server.
created_at: 2025-04-04T20:32:07Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-04-04T11:06:27Z
body: ###  🦋  Changeset detected

Latest commit: b31e52441df0f8339da64a8119c09a60f0ceb06d

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name          | Type  |
| ------------- | ----- |
| @clerk/nextjs | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/clerk/javascript/new/elef/sdki-972-add-support-for-redirecttosignup-from-middleware?filename=.changeset/early-points-argue.md&value=---%0A%22%40clerk%2Fbackend%22%3A%20patch%0A%22%40clerk%2Fnextjs%22%3A%20patch%0A---%0A%0Afeat(nextjs)%3A%20Support%20%60auth().redirectToSignUp()%60%0A)


author_association: NONE
user: login: vercel[bot]
created_at: 2025-04-04T11:06:28Z
body: [vc]: #ObXsvql1b+qAV0emVkavvqA0KxQSjXZzZ1cWP8JiT1E=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJjbGVyay1qcy1zYW5kYm94IiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9LCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vY2xlcmstcHJvZHVjdGlvbi9jbGVyay1qcy1zYW5kYm94LzJpZWJvZFd1VmpORWpITlNKa3JKSFhNZkE1THciLCJwcmV2aWV3VXJsIjoiIiwibmV4dENvbW1pdFN0YXR1cyI6IlNLSVBQRUQiLCJyb290RGlyZWN0b3J5IjoicGFja2FnZXMvY2xlcmstanMifV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)


<details><summary>1 Skipped Deployment</summary>

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **clerk-js-sandbox** | ⬜️ Skipped ([Inspect](https://vercel.com/clerk-production/clerk-js-sandbox/2iebodWuVjNEjHNSJkrJHXMfA5Lw)) |  |  | Apr 4, 2025 8:32pm |
</details>


author_association: NONE