[GH-ISSUE #73] Docs: recommended Clerk auth migration pattern (@clerk/backend + @clerk/react) #19

Open
opened 2026-05-06 12:36:33 +02:00 by BreizhHardware · 5 comments

Originally created by @solracnyc on GitHub (Feb 25, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/73

Context

vinext's compatibility map correctly flags @clerk/nextjs as unsupported. We hit this during migration — import { auth } from '@clerk/nextjs/server' crashes with require is not defined because the ESM build has a CJS dependency chain (require("server-only")).

We successfully migrated by splitting Clerk usage into two packages that work cleanly with vinext:

  • Server-side auth: @clerk/backendverifyToken() for JWKS-verified JWT auth, createClerkClient() for the Clerk API
  • Client-side components: @clerk/react (via @clerk/nextjs client-only imports like ClerkProvider, SignIn, useAuth) — these already work fine since they're React components, not server imports
  • Middleware: clerkMiddleware from @clerk/nextjs/server still works in proxy.ts since vinext handles middleware in a separate context

What we built

A drop-in auth() replacement (~60 lines) that:

  1. Reads x-clerk-auth-token and x-clerk-auth-status headers (set by clerkMiddleware)
  2. Verifies the JWT cryptographically via @clerk/backend's verifyToken() (JWKS cached after first call)
  3. Returns the same shape as @clerk/nextjs/server's auth()userId, orgId, orgRole, has(), redirectToSignIn()

This let us swap import { auth } from '@clerk/nextjs/server'import { auth } from '@/lib/auth' across 16 files with zero behavior change. All 197 tests pass with the same mock shapes.

Request

Would it be helpful to document this pattern in vinext's docs or compatibility guide? Clerk is a popular auth provider for Next.js apps, so other users migrating to vinext will likely hit the same issue. We're happy to contribute a docs PR if there's interest.

Environment

  • vinext: 0.0.8
  • @clerk/nextjs: 6.36.5
  • @clerk/backend: 2.29.0
  • Next.js: 16.1.6
Originally created by @solracnyc on GitHub (Feb 25, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/73 ## Context vinext's compatibility map correctly flags `@clerk/nextjs` as unsupported. We hit this during migration — `import { auth } from '@clerk/nextjs/server'` crashes with `require is not defined` because the ESM build has a CJS dependency chain (`require("server-only")`). We successfully migrated by splitting Clerk usage into two packages that work cleanly with vinext: - **Server-side auth**: `@clerk/backend` — `verifyToken()` for JWKS-verified JWT auth, `createClerkClient()` for the Clerk API - **Client-side components**: `@clerk/react` (via `@clerk/nextjs` client-only imports like `ClerkProvider`, `SignIn`, `useAuth`) — these already work fine since they're React components, not server imports - **Middleware**: `clerkMiddleware` from `@clerk/nextjs/server` still works in `proxy.ts` since vinext handles middleware in a separate context ## What we built A drop-in `auth()` replacement (~60 lines) that: 1. Reads `x-clerk-auth-token` and `x-clerk-auth-status` headers (set by `clerkMiddleware`) 2. Verifies the JWT cryptographically via `@clerk/backend`'s `verifyToken()` (JWKS cached after first call) 3. Returns the same shape as `@clerk/nextjs/server`'s `auth()` — `userId`, `orgId`, `orgRole`, `has()`, `redirectToSignIn()` This let us swap `import { auth } from '@clerk/nextjs/server'` → `import { auth } from '@/lib/auth'` across 16 files with zero behavior change. All 197 tests pass with the same mock shapes. ## Request Would it be helpful to document this pattern in vinext's docs or compatibility guide? Clerk is a popular auth provider for Next.js apps, so other users migrating to vinext will likely hit the same issue. We're happy to contribute a docs PR if there's interest. ## Environment - **vinext**: 0.0.8 - **@clerk/nextjs**: 6.36.5 - **@clerk/backend**: 2.29.0 - **Next.js**: 16.1.6
Author
Owner

@SuperJakov commented on GitHub (Feb 26, 2026):

If possible, it would be much better if we got require() support

<!-- gh-comment-id:3965975528 --> @SuperJakov commented on GitHub (Feb 26, 2026): If possible, it would be much better if we got `require()` support
Author
Owner

@solracnyc commented on GitHub (Feb 28, 2026):

Agreed — native require() support would be the cleanest path. Great to see @nikosdouvlis already tackling this on the Clerk side with clerk/javascript#7954, which makes @clerk/nextjs ESM-safe for non-Node.js runtimes like Workers/vinext.

We'll test with the new @clerk/nextjs version once it ships. If it works cleanly, the docs PR we offered may not be needed — or could be simplified to a one-liner in the compatibility notes.

In the meantime, our @clerk/backend adapter pattern (~60 lines) works today for anyone who needs Clerk auth on vinext before that fix lands. Happy to contribute docs if it's still useful.

<!-- gh-comment-id:3976500472 --> @solracnyc commented on GitHub (Feb 28, 2026): Agreed — native `require()` support would be the cleanest path. Great to see @nikosdouvlis already tackling this on the Clerk side with clerk/javascript#7954, which makes `@clerk/nextjs` ESM-safe for non-Node.js runtimes like Workers/vinext. We'll test with the new `@clerk/nextjs` version once it ships. If it works cleanly, the docs PR we offered may not be needed — or could be simplified to a one-liner in the compatibility notes. In the meantime, our `@clerk/backend` adapter pattern (~60 lines) works today for anyone who needs Clerk auth on vinext before that fix lands. Happy to contribute docs if it's still useful.
Author
Owner

@zebp commented on GitHub (Mar 1, 2026):

This should be fixed with #198 which landed in v0.0.16, please give it another try

<!-- gh-comment-id:3979885689 --> @zebp commented on GitHub (Mar 1, 2026): This should be fixed with #198 which landed in v0.0.16, please give it another try
Author
Owner

@nikosdouvlis commented on GitHub (Mar 2, 2026):

Thanks a lot for initial exploration @solracnyc :) we plan to tackle this one the Clerk side with changes in @clerk/nextjs (or a new package, I can't share details yet as I'm still exploring our options).

As for the require fix in 0.0.16 is definitely a step towards the right direction, thank you @zebp!

Posting here for visibility as I haven't been able to dive deeper yet (plan to work on this more within the next few hours), but I'm still getting the following error running vite dev (same results when trying to deploy to CF Workers):

require is not defined
    at src/runtime/node/safe-node-apis.js (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/runtime/node/safe-node-apis.js:5:88)
    at __require (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/dist/esm/chunk-BUSYA2B4.js?v=73173554:6:50)
    at eval (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/runtime/node/safe-node-apis.js:19:34)
    at async ESModulesEvaluator.runInlinedModule (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:913:3)
    at async ModuleRunner.directRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1146:59)
    at async ModuleRunner.cachedRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1053:73)
    at async eval (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/server/fs/utils.ts:5:1)
    at async ESModulesEvaluator.runInlinedModule (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:913:3)
    at async ModuleRunner.directRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1146:59)
    at async ModuleRunner.cachedRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1053:73)

The test app above uses vintext@0.0.18 and @clerk/nextjs@canary - build passes with the changes from https://github.com/clerk/javascript/pull/7954 but we still have middleware-level compat issues of course.

<!-- gh-comment-id:3984911517 --> @nikosdouvlis commented on GitHub (Mar 2, 2026): Thanks a lot for initial exploration @solracnyc :) we plan to tackle this one the Clerk side with changes in `@clerk/nextjs` (or a new package, I can't share details yet as I'm still exploring our options). As for the `require` fix in `0.0.16` is definitely a step towards the right direction, thank you @zebp! Posting here for visibility as I haven't been able to dive deeper yet (plan to work on this more within the next few hours), but I'm still getting the following error running `vite dev` (same results when trying to deploy to CF Workers): ```ts require is not defined at src/runtime/node/safe-node-apis.js (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/runtime/node/safe-node-apis.js:5:88) at __require (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/dist/esm/chunk-BUSYA2B4.js?v=73173554:6:50) at eval (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/runtime/node/safe-node-apis.js:19:34) at async ESModulesEvaluator.runInlinedModule (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:913:3) at async ModuleRunner.directRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1146:59) at async ModuleRunner.cachedRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1053:73) at async eval (/Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/@clerk+nextjs@7.0.0-canary.v20260227223209_next@16.1.6_react-dom@19.2.4_react@19.2.4__r_b01c410657eca58d465360d2432c5a2b/node_modules/@clerk/nextjs/src/server/fs/utils.ts:5:1) at async ESModulesEvaluator.runInlinedModule (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:913:3) at async ModuleRunner.directRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1146:59) at async ModuleRunner.cachedRequest (file:///Users/nikos/Projects/vinext-clerk-smoke-v2/node_modules/.pnpm/vite@7.3.1_@types+node@20.19.35_terser@5.46.0/node_modules/vite/dist/node/module-runner.js:1053:73) ``` The test app above uses `vintext@0.0.18` and `@clerk/nextjs@canary` - build passes with the changes from https://github.com/clerk/javascript/pull/7954 but we still have middleware-level compat issues of course.
Author
Owner

@solracnyc commented on GitHub (Mar 6, 2026):

Thanks @zebp! We're currently pinned to ~0.0.15 in production. We'll retest on a preview branch against the latest vinext release (0.0.21) and report back with dev/build/deploy results for native @clerk/nextjs on Workers.

We're also tracking clerk/javascript#7954 — noted that @nikosdouvlis reported build passes but vite dev and Workers deploy still fail as of vinext 0.0.18 + canary Clerk. Will include that combination in our test matrix.

<!-- gh-comment-id:4008870491 --> @solracnyc commented on GitHub (Mar 6, 2026): Thanks @zebp! We're currently pinned to `~0.0.15` in production. We'll retest on a preview branch against the latest vinext release (0.0.21) and report back with dev/build/deploy results for native `@clerk/nextjs` on Workers. We're also tracking clerk/javascript#7954 — noted that @nikosdouvlis reported build passes but `vite dev` and Workers deploy still fail as of vinext 0.0.18 + canary Clerk. Will include that combination in our test matrix.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#19
No description provided.