Skip to content

perf(auth): optimize getSession with in-memory fast-path and lockless… - #2618

Open
karan-963 wants to merge 1 commit into
supabase:masterfrom
karan-963:fix/issue-970-getsession-perf
Open

perf(auth): optimize getSession with in-memory fast-path and lockless…#2618
karan-963 wants to merge 1 commit into
supabase:masterfrom
karan-963:fix/issue-970-getsession-perf

Conversation

@karan-963

Copy link
Copy Markdown

perf(auth): optimize getSession with in-memory fast-path and lockless reads

🔍 Description

This PR resolves the performance degradation in supabase.auth.getSession() during initial component mounting and page rendering phases.

What changed?

  1. Lockless Read Routing: Removed exclusive lock acquisition (this._acquireLock) around getSession(). Read-only session lookups are idempotent and safe to execute concurrently without queuing behind mutual exclusion locks. Mutating operations (refreshSession, setSession, signOut) remain strictly guarded.
  2. In-Flight Single-Flighting (_inFlightLoadSession): Deduplicated concurrent initial calls to __loadSession(). When multiple components mount simultaneously, all callers share a single in-flight Promise, guaranteeing only 1 underlying storage read instead of $N$ sequential reads.
  3. In-Memory Cache Fast-Path (_inMemorySession): Cached valid, unexpired sessions in memory. Synchronized the cache with _saveSession, _removeSession, _notifyAllSubscribers, and token refreshes. Subsequent calls resolve in <0.001 ms (sub-microsecond).
  4. Caller Immutability Hardening (deepClone): Returned sessions on the fast-path pass through deepClone(this._inMemorySession) to guarantee that user application code mutating properties on session or user cannot corrupt the SDK's internal cache.

Why was this change needed?

When multiple components mount simultaneously during page rendering or hydration (e.g. in React / Next.js), calling supabase.auth.getSession() in parallel resulted in severe serialization latency (20ms to 450ms+ depending on storage and lock contention). Under async storage adapters (Next.js SSR cookies, React Native AsyncStorage) and custom locks (processLock, navigator.locks), each component waited in line for previous locks to release.

Closes #970


📸 Screenshots/Examples

1. In-Browser Live Benchmark Comparison (100 Concurrent Component Mounts)

(Tested live in browser engine with high-resolution timers performance.now(). Timings use ~ to reflect typical runtime variability across browser turns and hardware):

Scenario Before Fix (Unpatched v2.x) After Fix (Patched PR Build) Sync JWT Floor Observed Speedup
100 Components (Async Storage Mount) ~117 ms – ~452 ms ~0.70 ms – ~2.8 ms ~0.35 ms ~40x – ~167x faster
Per-Component Average Wait ~61 ms – ~218 ms ~0.58 ms – ~1.2 ms ~0.003 ms ~100x – ~375x faster
100 Components (Empty Storage / Logged Out) ~84 ms – ~350 ms ~0.40 ms – ~0.9 ms ~0.10 ms ~90x – ~200x faster
Subsequent Idle getSession() ~1.6 ms ~0.0008 ms ~0.003 ms Sub-microsecond

2. Live Interactive Test Harness

🌐 Live Demo (GitHub Pages): https://karan-963.github.io/supabase-js/

Side-by-Side 100-Component Mount & Real SDK Output:

image image copy ---

🔄 Breaking changes

  • This PR contains no breaking changes

📋 Checklist

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

📝 Additional notes

Security & Edge Cases Considered:

  1. Mutation by Reference (Caller Tampering): Returning this._inMemorySession directly could allow callers to mutate properties on data.session.user. We hardened the fast-path to return deepClone(this._inMemorySession).
  2. Direct Storage Clearing (localStorage.clear()): Calling localStorage.clear() externally leaves _inMemorySession until page reload or token expiry, consistent with standard token caching (Firebase Auth, Auth0). _removeSession() and signOut() remain the canonical eviction path.
  3. Audit Suite Verification (5/5 Browser Tests Passing):
    • Immutability / deepClone isolation: PASS
    • Empty storage cold-start (50 null sessions in ~0.40ms): PASS
    • SignOut memory and storage eviction: PASS
    • 1,000 concurrent calls hammer test (~9.80ms): PASS
    • Multi-tab BroadcastChannel event dispatch: PASS
  4. Unit Tests: All 144 / 144 unit tests pass (pnpm exec nx test:unit supabase-js).

@karan-963
karan-963 requested review from a team as code owners August 17, 2026 17:18
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7d26b636-1ccd-46f1-b38b-b08fd58b035b

📥 Commits

Reviewing files that changed from the base of the PR and between a249594 and ea26be2.

📒 Files selected for processing (1)
  • packages/core/auth-js/src/GoTrueClient.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

supabase.auth.getSession is slow

1 participant