# How to Set Environment Variables in Supabase

- Tool: Supabase
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Supabase (all plans), @supabase/supabase-js v2+, Next.js/Vite/Expo
- Last updated: March 2026

## TL;DR

Supabase projects have two main API keys: the anon key (safe for client-side, respects RLS) and the service role key (server-only, bypasses RLS). Find both in Dashboard > Settings > API. For local development, store them in .env.local. For Edge Functions, use supabase secrets set. Each frontend framework has its own prefix: NEXT_PUBLIC_ for Next.js, VITE_ for Vite/Lovable/V0, and EXPO_PUBLIC_ for Expo.

## Setting Environment Variables for Supabase Projects

Every Supabase project requires two environment variables to connect: the project URL and an API key. Understanding which key to use where is critical for security. The anon key is designed for client-side code and respects Row Level Security policies. The service role key bypasses all security and must only be used in server-side code. This tutorial shows you where to find these keys, how to configure them for your framework, and how to manage secrets for Edge Functions.

## Before you start

- A Supabase project created in the Dashboard
- A frontend project using Next.js, Vite, React, or another framework
- Basic understanding of environment variables and .env files

## Step-by-step guide

### 1. Find your API keys in the Supabase Dashboard

Go to the Supabase Dashboard, select your project, and navigate to Settings > API. You will see two sections: Project URL and Project API keys. The Project URL is your Supabase endpoint (e.g., https://abcdefgh.supabase.co). Under API keys, you have the anon (public) key and the service_role (secret) key. The anon key is safe to use in browser code because it respects RLS policies. The service role key bypasses all RLS and should never be exposed in client-side code.

```
# Your Supabase environment variables:
SUPABASE_URL=https://abcdefgh.supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

**Expected result:** You have copied your project URL, anon key, and service role key from the Dashboard.

### 2. Configure environment variables for Next.js

Next.js uses .env.local for local development environment variables. Variables prefixed with NEXT_PUBLIC_ are exposed to the browser. The Supabase URL and anon key need this prefix because the client runs in the browser. The service role key must NOT have the NEXT_PUBLIC_ prefix because it should only be available in server-side code (API routes, server components, middleware).

```
# .env.local (Next.js)

# Client-side (available in browser)
NEXT_PUBLIC_SUPABASE_URL=https://abcdefgh.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Server-side only (NOT exposed to browser)
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

**Expected result:** Your Next.js project reads Supabase keys from .env.local with proper NEXT_PUBLIC_ prefixing.

### 3. Configure environment variables for Vite, Lovable, and V0

Vite-based projects (including Lovable and V0 exports) use the VITE_ prefix for client-side variables. Only variables starting with VITE_ are available in browser code via import.meta.env. For Lovable projects, set environment variables in the Cloud tab > Secrets section. For V0 projects, set them in the Vars panel. When deploying to Vercel, use the Supabase integration or manually add the variables in Vercel's Environment Variables settings.

```
# .env.local (Vite / Lovable / V0)

# Client-side (available in browser)
VITE_SUPABASE_URL=https://abcdefgh.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Usage in code:
# const supabase = createClient(
#   import.meta.env.VITE_SUPABASE_URL,
#   import.meta.env.VITE_SUPABASE_ANON_KEY
# )
```

**Expected result:** Your Vite-based project accesses Supabase keys through import.meta.env with the VITE_ prefix.

### 4. Set secrets for Supabase Edge Functions

Edge Functions automatically have access to SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, and SUPABASE_DB_URL without any configuration. For additional secrets (like third-party API keys), use the supabase secrets set command. Secrets are encrypted and available via Deno.env.get() inside your functions. You do not need to redeploy functions after setting new secrets.

```
# Set a secret for Edge Functions
supabase secrets set STRIPE_SECRET_KEY=sk_live_abcdef123456

# Set multiple secrets from a file
supabase secrets set --env-file ./supabase/.env

# List current secrets
supabase secrets list

# Unset a secret
supabase secrets unset STRIPE_SECRET_KEY

# Access in Edge Function code:
# const stripeKey = Deno.env.get('STRIPE_SECRET_KEY')!
```

**Expected result:** Edge Function secrets are set and accessible via Deno.env.get() without redeploying.

### 5. Initialize the Supabase client with environment variables

With environment variables configured, create your Supabase client. For client-side code, use the anon key. For server-side code that needs to bypass RLS (admin operations, webhooks, cron jobs), use the service role key. Always create separate client instances for each purpose so you do not accidentally use the service role key in browser code.

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

// Client-side: uses anon key, respects RLS
export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)

// Server-side only: uses service role key, bypasses RLS
// NEVER import this in client-side code!
export const supabaseAdmin = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!,
  {
    auth: {
      autoRefreshToken: false,
      persistSession: false,
    },
  }
)
```

**Expected result:** Separate Supabase clients are configured for client-side (anon key) and server-side (service role key) usage.

## Complete code example

File: `supabase-env-setup.ts`

```typescript
// Complete environment variable setup for Supabase with Next.js
// File: src/lib/supabase.ts

import { createClient, SupabaseClient } from '@supabase/supabase-js'

// ============================================
// Client-side Supabase client
// Uses the anon key — safe for browser code
// Respects Row Level Security policies
// ============================================
export const supabase: SupabaseClient = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)

// ============================================
// Server-side admin client
// Uses the service role key — NEVER expose to browser!
// Bypasses all RLS policies
// Only import this in:
//   - API routes
//   - Server components
//   - Middleware
//   - Cron jobs / webhooks
// ============================================
export function createAdminClient(): SupabaseClient {
  if (typeof window !== 'undefined') {
    throw new Error(
      'createAdminClient must only be called on the server. ' +
      'The service role key bypasses RLS and must never be exposed to the browser.'
    )
  }

  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!,
    {
      auth: {
        autoRefreshToken: false,
        persistSession: false,
      },
    }
  )
}

// ============================================
// Environment variable reference:
//
// .env.local:
// NEXT_PUBLIC_SUPABASE_URL=https://abcdefgh.supabase.co
// NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...
// SUPABASE_SERVICE_ROLE_KEY=eyJhbGci...
//
// Edge Functions (set via CLI):
// supabase secrets set MY_SECRET_KEY=value
// Access: Deno.env.get('MY_SECRET_KEY')
// ============================================
```

## Common mistakes

- **Using the service role key in client-side code, exposing it to all users** — undefined Fix: Only use the service role key in server-side code (API routes, server components, Edge Functions). Use the anon key for all client-side Supabase operations.
- **Committing .env.local files to version control, leaking API keys** — undefined Fix: Add .env.local and .env to your .gitignore file. Use environment variable management in your deployment platform (Vercel, Netlify) for production.
- **Using the wrong prefix for the framework (e.g., NEXT_PUBLIC_ in a Vite project)** — undefined Fix: Use NEXT_PUBLIC_ for Next.js, VITE_ for Vite/Lovable/V0, EXPO_PUBLIC_ for Expo, and REACT_APP_ for Create React App. Only variables with the correct prefix are available in browser code.
- **Not setting SUPABASE_SERVICE_ROLE_KEY without NEXT_PUBLIC_ prefix, making it available in the browser** — undefined Fix: Never prefix the service role key with NEXT_PUBLIC_ or VITE_. It should only be accessible in server-side code.

## Best practices

- Always use the anon key for client-side code and the service role key only in server-side code
- Store environment variables in .env.local for development and in your deployment platform for production
- Add .env.local to .gitignore to prevent committing secrets to version control
- Use the correct framework prefix: NEXT_PUBLIC_ (Next.js), VITE_ (Vite), EXPO_PUBLIC_ (Expo)
- Create separate Supabase client instances for client-side and server-side admin operations
- For Edge Functions, use supabase secrets set instead of hardcoding values in function code
- Add a runtime check in your admin client to prevent it from being used in browser code

## Frequently asked questions

### What is the difference between the anon key and the service role key?

The anon key creates requests with the anon PostgreSQL role and respects all Row Level Security policies. It is safe for client-side code. The service role key bypasses all RLS policies and has full access to the database. It must only be used in server-side code.

### Can I regenerate my Supabase API keys?

You can reset your database password in Dashboard > Settings > Database. The API keys (anon and service role) are derived from your JWT secret and cannot be individually regenerated without changing the JWT secret, which invalidates all existing sessions.

### Do Supabase Edge Functions automatically have access to my API keys?

Yes. Edge Functions automatically have access to SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, and SUPABASE_DB_URL without any configuration. You only need to use supabase secrets set for additional third-party secrets.

### How do I set environment variables in Lovable?

In Lovable, click the Cloud tab (click the + button next to the Preview panel), then go to the Secrets section. Enter your key-value pairs there. Lovable encrypts and injects them into your project automatically.

### Should I use the anon key or service role key for server-side rendering?

Use the anon key with the user's session token for SSR. The session token authenticates the request as the user, and RLS policies apply. Only use the service role key for admin operations that need to bypass RLS, like creating users or accessing all records.

### What happens if I accidentally expose the service role key?

If the service role key is leaked, anyone can bypass all RLS policies and access or modify all data in your database. Immediately rotate the JWT secret in Dashboard > Settings > API and update all server-side code with the new keys. All existing sessions will be invalidated.

### Can RapidDev help secure my Supabase environment configuration?

Yes. RapidDev can audit your environment variable configuration, ensure API keys are not exposed in client-side code, set up proper secret management for Edge Functions, and configure deployment platforms with the correct variables.

---

Source: https://www.rapidevelopers.com/supabase-tutorial/how-to-set-environment-variables-in-supabase
© RapidDev — https://www.rapidevelopers.com/supabase-tutorial/how-to-set-environment-variables-in-supabase
