Each frontend framework only exposes environment variables that carry a specific prefix. Use the wrong prefix and your Supabase client gets undefined at runtime. Here are the exact names.
Vite (and Vite-based React)
Vite only exposes variables prefixed VITE_. In .env:
VITE_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY,
);
Next.js
Next.js exposes browser variables prefixed NEXT_PUBLIC_. In .env.local:
NEXT_PUBLIC_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
);
Server-only code (route handlers, server components) can read a non-public SUPABASE_SERVICE_ROLE_KEY — never give that value a NEXT_PUBLIC_ name.
Create React App
CRA uses the REACT_APP_ prefix:
REACT_APP_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
REACT_APP_SUPABASE_ANON_KEY=your-anon-key
Where these values come from
The URL and anon key both live in Project Settings → API in your Supabase dashboard — full walkthrough here.
Related
Building this app? Deploy it on Hostwares. Connect your repo and HW — our AI DevOps agent — handles the move: it detects your framework, provisions or wires your database, injects the env vars your app expects (DATABASE_URL, SUPABASE_URL, SUPABASE_ANON_KEY…), and sets up SSL. You review and go live.