Home

Fix this error · Supabase and Firebase

Fix: Error: supabaseUrl is required.

Fix "supabaseUrl is required." from createClient: missing NEXT_PUBLIC_ prefix, Vercel env not set for Preview, and the rebuild that inlines the value.

createClient from @supabase/supabase-js was called with an empty or undefined URL. The environment variable you pass in was not set where the code ran. In Next.js the usual causes are a missing NEXT_PUBLIC_ prefix on a variable read in the browser, a variable that Vercel has for Production but not for Preview, or a value added after the last build. Set the variable for the right environment and build again.

FactDetail
ErrorsupabaseUrl is required.
Close relativessupabaseKey is required. · Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL. · @supabase/ssr: Your project's URL and API key are required to create a Supabase client!
Where you see itBrowser console, next build output, Vercel build or function logs, the terminal
Usual causeprocess.env.NEXT_PUBLIC_SUPABASE_URL is undefined at build time or in that environment
Usual fixSet the variable for every environment that builds the app, then rebuild or redeploy
BugTape catches itAt request time on the server, and in the browser after BugTape starts. A failure at build time is only in your build log

What the error means

supabase-js validates the URL before it creates anything. It trims the value, and when nothing is left it throws Error('supabaseUrl is required.'). A value without http:// or https:// throws Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL. A missing key throws supabaseKey is required.

@supabase/ssr checks both values first and throws its own message. createBrowserClient says @supabase/ssr: Your project's URL and API key are required to create a Supabase client! and createServerClient says Your project's URL and Key are required to create a Supabase client! The cause and the fix are the same.

The ! in process.env.NEXT_PUBLIC_SUPABASE_URL! only tells TypeScript to stop warning. At runtime the value is still undefined.

Common causes

  1. The variable is not set in the environment that built the app. On Vercel each variable is set for Production, Preview, Development or custom environments. A variable only in Production is missing from every preview deployment.
  2. The variable was added after the last deployment. Vercel applies environment variable changes only to new deployments. Next.js inlines NEXT_PUBLIC_ values into the browser bundle at build time, so a new value needs a new build.
  3. The browser reads a variable without the NEXT_PUBLIC_ prefix. SUPABASE_URL exists on the server and is undefined in the browser.
  4. A dynamic lookup. process.env[name] or const env = process.env; env.NEXT_PUBLIC_SUPABASE_URL is not inlined, so it is undefined in the browser.
  5. The .env file is in the wrong place or has the wrong name. Next.js loads .env* files only from the project root. Files inside src/ are ignored. .env.local is not loaded when NODE_ENV is test.
  6. One Docker image or build is promoted to several environments. NEXT_PUBLIC_ values are frozen at build time, so the runtime environment cannot change them.
  7. Vite or another bundler. Vite exposes only variables prefixed with VITE_ through import.meta.env, so process.env.SUPABASE_URL is undefined there.

How to fix it

Set both variables with the names the code reads

# .env.local in the project root, next to package.json
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-publishable-key

Restart next dev after you change .env.local. The publishable key is safe in the browser. The secret key is not, and must never get a NEXT_PUBLIC_ prefix.

Set them for every Vercel environment and redeploy

vercel env add NEXT_PUBLIC_SUPABASE_URL production
vercel env add NEXT_PUBLIC_SUPABASE_URL preview
vercel env add NEXT_PUBLIC_SUPABASE_URL development
vercel env pull .env.local   # copy the Development values to your machine

Then start a new deployment. The existing ones keep the values they were built with.

Read the variables with static names

Write each variable out in full so Next.js can replace it at build time.

// lib/supabase/env.ts
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
const key = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY;

if (!url || !key) {
  throw new Error(
    'Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY. ' +
      'Set them for this environment and rebuild.',
  );
}

export const supabaseUrl = url;
export const supabasePublishableKey = key;

A clear message names the variable, which saves a search the next time it happens.

Create the client inside a function

A client created at the top of a module runs when the module is imported, which can be during next build or before anything else on the page has loaded. Creating it in a function moves the error to the first real use.

// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr';
import { supabaseUrl, supabasePublishableKey } from './env';

export function createClient() {
  return createBrowserClient(supabaseUrl, supabasePublishableKey);
}

Use the Vite prefix in Vite apps

import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
);

How to catch it in production with BugTape

Where this error happens decides whether BugTape sees it.

  • During next build. When a page is prerendered, the error fails the build. Nothing is running yet, so no SDK reports it. Read the build log.
  • On the server at request time. The Node.js SDK reports errors thrown in pages, Route Handlers, Server Actions and the proxy through Next.js onRequestError, on the Node.js runtime. The Edge runtime is not supported.
  • In the browser. The browser SDK reports uncaught errors as soon as init() has run. A client created at the top of a module that loads with the first page can throw before BugTape starts, and that one is missed. A client created inside a function, on first use, is reported with the page URL and the steps before it.

Wire the server side once:

// instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') (await import('@bugtape/node')).init({ service: 'web' });
}

export async function onRequestError(...args: Parameters<typeof import('@bugtape/node').captureRequestError>) {
  if (process.env.NEXT_RUNTIME === 'nodejs') await (await import('@bugtape/node')).captureRequestError(...args);
}

For a missing variable you detect yourself, report it and keep the page usable. In the browser, reportError(err) fires the same window error event the SDK listens for. On the server, call bugtape.captureException(err).

Every visitor to a broken deployment hits the same line, so the reports group into one issue with a count. Set release (on Vercel, VERCEL_GIT_COMMIT_SHA, which the Node.js SDK reads on its own) so you can see which deployment is missing the value, and a fix that does not hold reopens as a regression. Your coding agent can read the issue over MCP (npx -y bugtape connect claude, or cursor or codex). You review the pull request.

FAQ

Why does it work locally but fail on Vercel?

Your machine reads .env.local, which Vercel never sees. Add the variables in the project settings for each environment you deploy, then start a new deployment.

Why does it work in production but fail in preview deployments?

The variable is set only for Production. Preview deployments use the Preview environment. Add the variable there, or for a specific branch, and redeploy.

I set the variable but the error is still there. Why?

NEXT_PUBLIC_ values are copied into the JavaScript bundle when the app is built. Changing the variable does not change a build that already exists. Start a new build. Locally, restart next dev.

Is it safe to put the Supabase URL and key in NEXT_PUBLIC_ variables?

The project URL and the publishable (anon) key are meant for the browser. Your data is protected by row-level security policies. The secret key, or the legacy service_role key, bypasses those policies and must stay in server-only variables.

Sources

All guides: Fix an error.

Start free. Free plan · No credit card · Set up in minutes. Or try the live demo first.