Documentation Index Fetch the complete documentation index at: https://mintlify.com/supabase/supabase/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Environment variables allow you to store secrets, API keys, and configuration outside your code. Supabase provides both built-in environment variables and custom secrets management.
Never commit secrets to version control. Always use environment variables for sensitive data.
Built-in Environment Variables
Supabase automatically provides these environment variables to all functions:
Variable Description Example SUPABASE_URLYour project’s API URL https://xxx.supabase.coSUPABASE_ANON_KEYYour project’s anon key eyJhbGc...SUPABASE_SERVICE_ROLE_KEYService role key (use with caution) eyJhbGc...SUPABASE_DB_URLPostgreSQL connection string postgresql://...
Access Built-in Variables
Deno . serve ( async ( req ) => {
// Access built-in variables
const supabaseUrl = Deno . env . get ( 'SUPABASE_URL' )
const supabaseKey = Deno . env . get ( 'SUPABASE_ANON_KEY' )
console . log ( 'Project URL:' , supabaseUrl )
return new Response ( 'OK' )
})
Built-in variables are automatically configured and don’t need to be set manually.
Custom Environment Variables
Set Secrets
Set custom secrets using the CLI:
supabase secrets set OPENAI_API_KEY=sk-proj-xxx
Set multiple secrets:
supabase secrets set OPENAI_API_KEY=sk-proj-xxx STRIPE_SECRET=sk_test_xxx
Set from File
Set multiple secrets from a file:
# Create secrets file
cat > .env.production << EOF
OPENAI_API_KEY=sk-proj-xxx
STRIPE_SECRET=sk_test_xxx
RESEND_API_KEY=re_xxx
EOF
# Set all secrets at once
supabase secrets set --env-file .env.production
Don’t commit .env.production or any secrets file to git. Add them to .gitignore.
List Secrets
View all configured secrets (values are hidden):
Output:
Name Value (truncated)
OPENAI_API_KEY sk-proj-***
STRIPE_SECRET sk_test_***
RESEND_API_KEY re_***
SUPABASE_URL https://***
SUPABASE_ANON_KEY eyJh***
Unset Secrets
Remove a secret:
supabase secrets unset OPENAI_API_KEY
Using Environment Variables
In Your Functions
Access environment variables with Deno.env.get():
Deno . serve ( async ( req ) => {
// Get environment variable
const apiKey = Deno . env . get ( 'OPENAI_API_KEY' )
if ( ! apiKey ) {
return new Response (
JSON . stringify ({ error: 'OPENAI_API_KEY not configured' }),
{ status: 500 }
)
}
// Use the API key
const response = await fetch ( 'https://api.openai.com/v1/completions' , {
headers: {
'Authorization' : `Bearer ${ apiKey } ` ,
'Content-Type' : 'application/json'
},
method: 'POST' ,
body: JSON . stringify ({ prompt: 'Hello' })
})
const data = await response . json ()
return new Response ( JSON . stringify ( data ))
})
With Type Safety
Create a helper for type-safe environment variables:
// supabase/functions/_shared/env.ts
export function getEnv ( key : string ) : string {
const value = Deno . env . get ( key )
if ( ! value ) {
throw new Error ( `Environment variable ${ key } is not set` )
}
return value
}
export function getOptionalEnv ( key : string , defaultValue : string ) : string {
return Deno . env . get ( key ) ?? defaultValue
}
Use in your function:
import { getEnv , getOptionalEnv } from '../_shared/env.ts'
Deno . serve ( async ( req ) => {
// Will throw if not set
const apiKey = getEnv ( 'OPENAI_API_KEY' )
// Optional with default
const model = getOptionalEnv ( 'OPENAI_MODEL' , 'gpt-3.5-turbo' )
// Use variables
console . log ( 'Using model:' , model )
})
Local Development
Create Local Environment File
Create .env.local for local development:
# supabase/.env.local
OPENAI_API_KEY = sk-proj-xxx
STRIPE_SECRET = sk_test_xxx
RESEND_API_KEY = re_xxx
Add to .gitignore:
echo "supabase/.env.local" >> .gitignore
Use Local Environment Variables
Serve functions with local environment:
supabase functions serve --env-file ./supabase/.env.local
Or for all commands:
supabase start --env-file ./supabase/.env.local
Example Local Setup
Create a complete local environment:
# Copy example to actual file
cp supabase/.env.example supabase/.env.local
# Edit with your local secrets
vim supabase/.env.local
# Start services
supabase start
# Serve function with local env
supabase functions serve --env-file ./supabase/.env.local
Real-World Examples
OpenAI Integration
Securely use OpenAI API:
Deno . serve ( async ( req ) => {
const apiKey = Deno . env . get ( 'OPENAI_API_KEY' )
if ( ! apiKey ) {
return new Response (
JSON . stringify ({ error: 'OpenAI API key not configured' }),
{ status: 500 , headers: { 'Content-Type' : 'application/json' } }
)
}
const { prompt } = await req . json ()
const response = await fetch ( 'https://api.openai.com/v1/chat/completions' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ apiKey } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
model: 'gpt-4' ,
messages: [{ role: 'user' , content: prompt }]
})
})
const data = await response . json ()
return new Response ( JSON . stringify ( data ), {
headers: { 'Content-Type' : 'application/json' }
})
})
Set the secret:
supabase secrets set OPENAI_API_KEY=sk-proj-xxx
Stripe Webhooks
Verify Stripe webhook signatures:
import Stripe from 'https://esm.sh/stripe@14?target=denonext'
const stripe = new Stripe ( Deno . env . get ( 'STRIPE_API_KEY' ) as string , {
apiVersion: '2024-11-20'
})
const cryptoProvider = Stripe . createSubtleCryptoProvider ()
Deno . serve ( async ( request ) => {
const signature = request . headers . get ( 'Stripe-Signature' )
const body = await request . text ()
try {
const event = await stripe . webhooks . constructEventAsync (
body ,
signature ! ,
Deno . env . get ( 'STRIPE_WEBHOOK_SIGNING_SECRET' ) ! ,
undefined ,
cryptoProvider
)
console . log ( `Event received: ${ event . id } ` )
// Process event
return new Response ( JSON . stringify ({ ok: true }), { status: 200 })
} catch ( err ) {
console . error ( 'Webhook signature verification failed:' , err )
return new Response ( err . message , { status: 400 })
}
})
Set secrets:
supabase secrets set STRIPE_API_KEY=sk_test_xxx
supabase secrets set STRIPE_WEBHOOK_SIGNING_SECRET=whsec_xxx
Email with Resend
Send emails securely:
const RESEND_API_KEY = Deno . env . get ( 'RESEND_API_KEY' )
Deno . serve ( async ( req ) => {
if ( ! RESEND_API_KEY ) {
return new Response ( 'RESEND_API_KEY not configured' , { status: 500 })
}
const { to , subject , html } = await req . json ()
const response = await fetch ( 'https://api.resend.com/emails' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ RESEND_API_KEY } `
},
body: JSON . stringify ({
from: 'noreply@yourdomain.com' ,
to ,
subject ,
html
})
})
const data = await response . json ()
return new Response ( JSON . stringify ( data ), {
headers: { 'Content-Type' : 'application/json' }
})
})
Database Connection
Connect directly to PostgreSQL:
import { Pool } from 'https://deno.land/x/postgres@v0.17.0/mod.ts'
const pool = new Pool (
{
tls: { enabled: false },
database: 'postgres' ,
hostname: Deno . env . get ( 'DB_HOSTNAME' ),
user: Deno . env . get ( 'DB_USER' ),
port: 6543 ,
password: Deno . env . get ( 'DB_PASSWORD' )
},
1
)
Deno . serve ( async ( _req ) => {
try {
const connection = await pool . connect ()
try {
const result = await connection . queryObject `SELECT * FROM animals`
const animals = result . rows
return new Response ( JSON . stringify ( animals , null , 2 ), {
headers: { 'Content-Type' : 'application/json' }
})
} finally {
connection . release ()
}
} catch ( err ) {
console . error ( err )
return new Response ( String ( err ?. message ?? err ), { status: 500 })
}
})
CI/CD Integration
GitHub Actions
Set secrets in GitHub Actions:
name : Deploy Functions
on :
push :
branches :
- main
jobs :
deploy :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v3
- uses : supabase/setup-cli@v1
with :
version : latest
- name : Set secrets
env :
SUPABASE_ACCESS_TOKEN : ${{ secrets.SUPABASE_ACCESS_TOKEN }}
run : |
supabase secrets set OPENAI_API_KEY="${{ secrets.OPENAI_API_KEY }}" --project-ref ${{ secrets.PROJECT_ID }}
supabase secrets set STRIPE_SECRET="${{ secrets.STRIPE_SECRET }}" --project-ref ${{ secrets.PROJECT_ID }}
- name : Deploy
env :
SUPABASE_ACCESS_TOKEN : ${{ secrets.SUPABASE_ACCESS_TOKEN }}
run : |
supabase functions deploy --project-ref ${{ secrets.PROJECT_ID }}
Configure GitHub secrets:
Go to Settings > Secrets and variables > Actions
Add each secret:
SUPABASE_ACCESS_TOKEN
PROJECT_ID
OPENAI_API_KEY
STRIPE_SECRET
Environment-Specific Secrets
Use different secrets for staging and production:
- name : Deploy to staging
if : github.ref == 'refs/heads/staging'
run : |
supabase secrets set OPENAI_API_KEY="${{ secrets.STAGING_OPENAI_KEY }}" --project-ref ${{ secrets.STAGING_PROJECT_ID }}
supabase functions deploy --project-ref ${{ secrets.STAGING_PROJECT_ID }}
- name : Deploy to production
if : github.ref == 'refs/heads/main'
run : |
supabase secrets set OPENAI_API_KEY="${{ secrets.PROD_OPENAI_KEY }}" --project-ref ${{ secrets.PROD_PROJECT_ID }}
supabase functions deploy --project-ref ${{ secrets.PROD_PROJECT_ID }}
Best Practices
Never Hardcode Secrets
// Don't do this!
const apiKey = 'sk-proj-1234567890abcdef'
fetch ( 'https://api.openai.com/v1/chat/completions' , {
headers: { 'Authorization' : `Bearer ${ apiKey } ` }
})
Validate Environment Variables
Check variables at startup:
const REQUIRED_ENV_VARS = [
'OPENAI_API_KEY' ,
'STRIPE_SECRET' ,
'RESEND_API_KEY'
]
function validateEnv () {
const missing = REQUIRED_ENV_VARS . filter ( key => ! Deno . env . get ( key ))
if ( missing . length > 0 ) {
throw new Error (
`Missing required environment variables: ${ missing . join ( ', ' ) } `
)
}
}
validateEnv ()
Deno . serve ( async ( req ) => {
// All required variables are set
})
Use .env.example
Provide a template for developers:
# supabase/.env.example
OPENAI_API_KEY = sk-proj-your-key-here
STRIPE_SECRET = sk_test_your-secret-here
RESEND_API_KEY = re_your-key-here
Developers copy and fill in their values:
cp supabase/.env.example supabase/.env.local
# Edit .env.local with actual values
Rotate Secrets Regularly
Update secrets periodically:
# Generate new API key
# Update secret
supabase secrets set OPENAI_API_KEY=sk-proj-new-key
# Verify
supabase secrets list
Troubleshooting
Secret Not Available
If a secret isn’t available:
Check if set :
Set the secret :
supabase secrets set KEY=value
Redeploy the function :
supabase functions deploy function-name
Local vs Production Differences
If behavior differs between local and production:
Compare secrets :
# Local
cat supabase/.env.local
# Production
supabase secrets list
Ensure consistency between environments
Test with production values locally when debugging
Next Steps
Debugging Debug and monitor your Edge Functions
Deploy Functions Learn deployment strategies