Skip to content

Conversation

@7ttp
Copy link

@7ttp 7ttp commented Nov 9, 2025

Next.js 16 App Router enforces deterministic rendering for Server Components.
The previous uuid() implementation in @supabase/auth-js relied on Math.random(),
which caused prerender errors even when no queries were executed.

This update replaces Math.random() with crypto.getRandomValues in browsers
and crypto.randomFillSync in Node, providing SSR-safe, fully synchronous UUID v4 generation.

Changes

  • Refactored uuid() in packages/auth-js/src/lib/helpers.ts
  • Fully synchronous and UUID v4 compliant
  • Compatible with Node 16+ and modern browsers
  • Resolves SSR/deterministic rendering errors caused by Math.random()

Closes #40273


🔍 Description

Fixes SSR prerender errors in Next.js 16 caused by Math.random() in uuid().

What changed?

Replaced Math.random() with crypto.getRandomValues in browsers and crypto.randomFillSync in Node. Updated uuid() to remain fully synchronous and UUID v4 compliant.

Why was this change needed?

To ensure Server Components render deterministically and prevent Next.js 16 prerender errors.

📸 Screenshots/Examples

N/A — code change only.

🔄 Breaking changes

  • This PR contains no breaking changes

📋 Checklist

  • I have read the Contributing Guidelines
  • My PR title follows the conventional commit format
  • I have run npx nx format to ensure consistent code formatting
  • I have added tests for new functionality (if applicable)
  • I have updated documentation (if applicable)

📝 Additional notes

This is a low-level crypto fix; no functional changes to existing APIs.

…ext.js 16 SSR

Next.js 16 App Router requires deterministic rendering for Server Components. 
The previous implementation of uuid() in @supabase/auth-js used Math.random(), 
which caused prerender errors even when no queries were executed.

This update replaces Math.random() with crypto.getRandomValues in browsers 
and crypto.randomFillSync in Node, providing SSR-safe, fully synchronous UUID v4 generation.

### Changes
- Refactored uuid() in packages/auth-js/src/lib/helpers.ts
- Fully synchronous and UUID v4 compliant
- Compatible with Node 16+ and modern browsers
- Resolves SSR/deterministic rendering errors caused by Math.random()

Closes #40273
@7ttp 7ttp requested review from a team as code owners November 9, 2025 10:39
@mandarini mandarini changed the title fix(auth-js): replace Math.random with crypto based UUID to support N… fix(auth): replace Math.random with crypto based UUID to support N… Nov 10, 2025
@mandarini
Copy link
Contributor

@7ttp thank you SO much for your contribution! Can you make sure that npx nx run-many --target=build is successful, and all packages build successfully?

@mandarini mandarini self-assigned this Nov 10, 2025
@BOXNYC
Copy link

BOXNYC commented Nov 10, 2025

I originally tried using crypto.getRandomValues() and the same build fail as Math.random(). Using performance.now() works for Next@16 cacheComponent testing.

Copy link
Contributor

@mandarini mandarini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@7ttp please make sure that build works, and maybe check out what @BOXNYC is suggesting!

Thank you very much for your contribution!

@BOXNYC
Copy link

BOXNYC commented Nov 10, 2025

@7ttp please make sure that build works, and maybe check out what @BOXNYC is suggesting!

Thank you very much for your contribution!

PR

@mandarini
Copy link
Contributor

Thanks for this PR! This is the cryptographically correct approach for UUID generation.

However, we've received reports from @BOXNYC (see #1844) that crypto.getRandomValues() also fails Next.js 16 builds with the same prerender error:

  > "Route "/" used [non-deterministic operation] before accessing either uncached data."

This suggests the issue isn't just Math.random() - Next.js 16 blocks all non-deterministic operations during pre-rendering, including crypto APIs.

Root Cause

The real problem is that createBrowserClient() generates UUIDs during initialization, which happens during Next.js pre-rendering. Since this is a browser client, UUID generation should be deferred to actual client-side execution where:

  • Crypto APIs work without restrictions
  • There's no determinism requirement
  • Security is maintained

I need to discuss with the team what the best approach to move forward is.

This PR has the right crypto implementation, but we need architectural changes to make it work with Next.js 16.

Until we fix this properly, users can defer client initialization to avoid pre-rendering, or disable SSR for the provider component.

@mandarini mandarini added the do-not-merge Do not merge this PR. label Nov 10, 2025
@mandarini
Copy link
Contributor

I am working on a solution here: #1847

Will give you @7ttp and @BOXNYC credits if we go ahead with solution

@7ttp
Copy link
Author

7ttp commented Nov 10, 2025

Glad to see progress on #1847
thanks @mandarini for mentioning credit!

@mandarini
Copy link
Contributor

Closing this in favor of #1847

@mandarini mandarini closed this Nov 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge Do not merge this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Next.js 16: createBrowserClient() used Math.random() inside a Client Component without a Suspense boundary above it

3 participants