Supabase: CORS errors from browser [2026 fix]

Browser blocks Supabase requests due to missing CORS headers. Add your domain to Project Settings > CORS or use API Gateway.

Supabase CORS Errors from Browser — 2am Fix

TL;DR

Cause: Your browser is blocking requests to Supabase because your domain isn't whitelisted in CORS settings.

Fix: Add your frontend domain to Supabase Project Settings > API > CORS configuration, or switch to using the built-in API Gateway.

---

Exact Error Messages You'll See

``` Access to XMLHttpRequest at 'https://xxxxx.supabase.co/rest/v1/users' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. ```

``` CORS error: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. ```

``` Failed to load resource: the server responded with a status of 403 (Forbidden) [Error] Failed to fetch (anonymous) @ index.js:45 ```

``` Access-Control-Allow-Origin: http://localhost:3000 is missing Fetch API cannot load https://xxxxx.supabase.co/rest/v1/... ```

``` Preflight request failed: No 'Access-Control-Allow-Origin' header status code: 0, status text: '' ```

---

The Broken Code vs. The Fix

Scenario 1: Missing CORS Configuration

Broken Code (doesn't tell Supabase to allow your domain): ```javascript // frontend/pages/api/users.js import { createClient } from '@supabase/supabase-js'

const supabase = createClient( 'https://xxxxx.supabase.co', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' )

// This request fails with CORS error const { data, error } = await supabase .from('users') .select('*') ```

Exact Fix:

1. In Supabase Dashboard → Your Project → Settings → API → CORS Configuration 2. Add your domain: ``` http://localhost:3000 https://yourdomain.com https://*.yourdomain.com ``` 3. Save & deploy 4. Your code now works without changes

Scenario 2: Using Credentials Without CORS Headers

Broken Code: ```javascript const { data, error } = await fetch( 'https://xxxxx.supabase.co/rest/v1/users', { method: 'GET', headers: { 'apikey': process.env.REACT_APP_SUPABASE_ANON_KEY, 'Authorization': Bearer ${session.access_token} }, credentials: 'include' // ← CORS will fail } ) ```

Exact Fix: ```javascript const { data, error } = await fetch( 'https://xxxxx.supabase.co/rest/v1/users', { method: 'GET', headers: { 'apikey': process.env.REACT_APP_SUPABASE_ANON_KEY, 'Authorization': Bearer ${session.access_token}, 'Content-Type': 'application/json' } // Remove credentials: 'include' if not needed // OR configure CORS to allow credentials } ) ```

Scenario 3: Using API Gateway (Recommended Alternative)

Alternative Fix (avoids CORS entirely):

```javascript // Use Supabase's API Gateway instead of direct REST endpoint const supabase = createClient( 'https://xxxxx.supabase.co', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', { realtime: { params: { eventsPerSecond: 10 } } } )

// This bypasses CORS issues entirely const { data } = await supabase.from('users').select('*') ```

---

Step-by-Step: Add Domain to CORS

1. Open Supabase Dashboard 2. Select your project 3. Click Settings (bottom left) 4. Go to API tab 5. Scroll to CORS Configuration 6. Click Add a domain 7. Enter: http://localhost:3000 (dev) or https://yourdomain.com (prod) 8. Click Save 9. Wait 30-60 seconds for propagation 10. Refresh browser and retry

---

Still Broken? Check These Too

1. Localhost domain mismatch: You added http://localhost:3000 but accessing from http://127.0.0.1:3000? They're different origins. Add both.

2. Port number changed: Development servers often shift ports (3000 → 3001). CORS whitelist is exact. Add all possible ports: http://localhost:3000, http://localhost:3001, etc.

3. Browser cache corrupting headers: Hard refresh (Ctrl+Shift+R or Cmd+Shift+R) and clear Site Data. Old CORS rejection responses cache for 10 minutes.

4. Using wildcard incorrectly: https://*.yourdomain.com works, but *.yourdomain.com without protocol doesn't. Always include https:// or http://.

---

Version Notes

I'm uncertain whether CORS behavior changed between Supabase SDK v1 → v2 regarding default credentials handling. Test with your exact version number (check package.json) and report results in comments if you hit unexpected behavior.

---

Related Guides

  • [Supabase authentication session expires instantly [fix]](/?guide=supabase-session-expiry)
  • [RLS policies blocking all queries [debugging]](/?guide=supabase-rls-debug)
  • ---

    Official Documentation

    [Supabase CORS Configuration](https://supabase.com/docs/guides/api/cors)

    ---

    Found a different variation? Drop it in the comments.

    🔥 0d
    LIVE
    ↓ PlanetScale rage spiking •⚠ Vercel pricing complaints •↑ Railway gaining fast •↑ Supabase happiness rising •↑ Resend loved by devs •↓ PlanetScale rage spiking •⚠ Vercel pricing complaints •↑ Railway gaining fast •↑ Supabase happiness rising
    DEVELOPER PAIN RADAR // Loading...

    Developers complain.
    Opportunities appear.

    We track what developers are struggling with today — and what opportunities that creates.

    —
    guides today
    —
    avg happiness
    🔥 Pain
    📖 Guides
    🔭 Explore
    👤 Mine
    🔥 Pain Radar — rage scores today
    ↗ share
    💡 Opportunity Feed — pain = market gap
    📈 Tool Momentum
    all scores →
    📖 Latest Guide
    all guides →
    📖 All Guides
    📊 Tool Scores
    + Submit
    📰 Hacker News
    ➕ Submit a Tool
    ← back