This guide will walk you through setting up Supabase for authentication, database, and backend services.
- Overview
- Prerequisites
- Project Setup
- Authentication Configuration
- Database Setup
- Environment Variables
- Row Level Security (RLS)
- Testing
- Production Deployment
- API Key System (Publishable & Secret Keys)
Supabase provides:
- Authentication - Email/password, OAuth providers (Google, GitHub)
- PostgreSQL Database - Fully managed, scalable database
- Row Level Security - Fine-grained access control at the database level
- Real-time Subscriptions - Live data updates (optional)
- Storage - File storage with security rules (optional)
Frontend (Next.js)
↓
Supabase Client (@supabase/ssr)
↓
Supabase Auth ←→ Supabase Database
↑
API Routes (Service Role Key)
- Supabase Account: Sign up for Supabase
- Node.js 18+: Required for the application
- Yarn: Package manager
- Go to Supabase Dashboard
- Click New Project
- Fill in:
- Name: Your project name (e.g.,
myimageupscaler.com) - Database Password: Generate a strong password (save it!)
- Region: Choose closest to your users
- Name: Your project name (e.g.,
- Click Create new project
- Wait for project to initialize (1-2 minutes)
- Go to Settings → API in the Supabase Dashboard
- Copy these values:
| Key | Format | Description | Usage |
|---|---|---|---|
| Project URL | https://xxxxx.supabase.co |
Your project's API endpoint | Public, client-side |
| Publishable key | sb_publishable_... |
New format (recommended) | Public, client-side |
| Secret key | sb_secret_... |
New format (recommended) | Server-side ONLY |
| anon (legacy) | eyJhbGci... (JWT) |
Legacy format | Public, client-side |
| service_role (legacy) | eyJhbGci... (JWT) |
Legacy format | Server-side ONLY |
Note: Supabase now offers new
publishableandsecretkeys with better security and performance. See API Key System for details. Both key systems work simultaneously.
Security Warning:
- The
anon/publishablekey is safe to expose in client-side code - The
service_role/secretkey bypasses RLS - NEVER expose to clients
Go to Authentication → Providers:
- Email authentication is enabled by default
- Configure whether users need to verify their email to sign in (enabled by default on hosted projects)
See the detailed Google OAuth Setup Guide for step-by-step instructions including:
- Creating a Google Cloud project
- Configuring OAuth consent screen
- Setting up credentials
See the detailed GitHub OAuth Setup Guide for step-by-step instructions including:
- Creating a GitHub OAuth App
- Configuring callback URLs
- Handling private emails
Go to Authentication → URL Configuration:
| Setting | Development | Production |
|---|---|---|
| Site URL | http://localhost:3000 |
https://yourdomain.com |
| Redirect URLs | http://localhost:3000/** |
https://yourdomain.com/** |
Tip: Use wildcard
/**to allow any path on these domains. The globstar (**) matches any sequence of characters including path separators.
Go to Authentication → Templates to customize:
- Confirm signup
- Reset password
- Magic link
- Email change
Note: For production use, consider configuring a custom SMTP server. The default email service has a rate limit and is on a best-effort basis. See the Custom SMTP guide for instructions.
This project includes migration files in supabase/migrations/ and a setup script to apply them.
Use the setup script to apply all migrations:
# Run the setup script
./scripts/setup-supabase.sh
# Or generate SQL for manual execution
./scripts/setup-supabase.sh --manualScript options:
| Flag | Description |
|---|---|
--manual |
Generate combined SQL file for Supabase Dashboard |
--dry-run |
Preview what would be executed |
--skip-verify |
Skip verification checklist |
- Go to Supabase Dashboard → SQL Editor
- Run migrations in order from
supabase/migrations/:20250120_create_profiles_table.sql20250120_create_subscriptions_table.sql20250121_create_credit_transactions_table.sql20250121_create_processing_jobs_table.sql20250120_create_rpc_functions.sql20250121_enhanced_credit_functions.sql20250121_fix_initial_credits.sql
| Type | Name | Description |
|---|---|---|
| Tables | profiles |
User profiles with credits balance |
subscriptions |
Stripe subscription records | |
credit_transactions |
Credit usage/purchase history | |
processing_jobs |
Background job tracking | |
| Functions | increment_credits |
Add credits to user |
decrement_credits |
Use credits | |
has_sufficient_credits |
Check balance | |
get_active_subscription |
Get user's subscription | |
| Triggers | on_auth_user_created |
Auto-create profile on signup |
Run this query to verify tables were created:
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' ORDER BY table_name;Expected tables: credit_transactions, processing_jobs, profiles, subscriptions
Create two environment files:
.env - Public variables:
# Supabase - Get from: Supabase Dashboard > Settings > API
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# App
NEXT_PUBLIC_BASE_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME=MyImageUpscaler.env.prod - Server-side secrets (NEVER commit):
# Supabase - Get from: Supabase Dashboard > Settings > API
# This is the service_role key (NOT anon key)
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...- Go to Supabase Dashboard
- Select your project
- Navigate to Settings → API
- Copy the values:
| Dashboard Field | Environment Variable |
|---|---|
| Project URL | NEXT_PUBLIC_SUPABASE_URL |
| anon public | NEXT_PUBLIC_SUPABASE_ANON_KEY |
| service_role | SUPABASE_SERVICE_ROLE_KEY |
| Variable | Exposure | Usage |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Public (client) | Used in browser |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Public (client) | Used in browser, respects RLS |
SUPABASE_SERVICE_ROLE_KEY |
Server ONLY | Bypasses RLS, use in API routes only |
RLS policies control who can access what data at the database level.
-- Users can only see their own profile
CREATE POLICY "Users can view own profile"
ON public.profiles FOR SELECT
USING (auth.uid() = id);This means:
auth.uid()returns the current authenticated user's IDidis the profile's ID- The policy only returns rows where these match
| Table | Policy | Description |
|---|---|---|
| profiles | SELECT own | Users see only their profile |
| profiles | UPDATE own | Users update only their profile |
| subscriptions | SELECT own | Users see only their subscriptions |
| credit_transactions | SELECT own | Users see only their transactions |
The service_role key bypasses ALL RLS policies. Use it only in:
- API routes (server-side)
- Webhooks
- Admin operations
- E2E tests
// Client-side (respects RLS)
const supabase = createBrowserClient(url, anonKey);
// Server-side (bypasses RLS)
const supabaseAdmin = createClient(url, serviceRoleKey);-
Start the development server:
yarn dev
-
Navigate to
http://localhost:3000 -
Click "Sign In" and test:
- Email/password signup
- Email/password login
- OAuth login (if configured)
-- In Supabase SQL Editor
-- Check if profiles are created on signup
SELECT * FROM profiles LIMIT 5;
-- Check RLS is working (should return nothing when not authenticated)
SELECT * FROM profiles;
-- Test RPC function
SELECT add_credits('user-uuid-here', 100, 'test', 'test-ref', 'Test credits');# Health check
curl http://localhost:3000/api/health
# Billing info (requires auth)
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:3000/api/billingBilling E2E tests require the service role key:
# Ensure .env.prod has SUPABASE_SERVICE_ROLE_KEY
yarn test:e2eSee E2E Testing Setup Guide for details.
Set environment variables in Cloudflare Dashboard:
- Go to Workers & Pages → Your Project → Settings → Environment Variables
- Add:
| Variable | Type |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Plain text |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Plain text |
SUPABASE_SERVICE_ROLE_KEY |
Encrypted |
- Run all database migrations in production Supabase
- Verify RLS policies are enabled on all tables
- Set production Site URL in Supabase Auth settings
- Add production domain to Redirect URLs
- Configure OAuth providers with production URLs
- Set all environment variables in Cloudflare
- Test authentication flow in production
- Monitor Supabase logs for errors
- Supabase Dashboard → Logs - Database and auth logs
- Supabase Dashboard → Reports - Usage statistics
- Supabase Dashboard → Database → Roles - Check permissions
- Verify
NEXT_PUBLIC_SUPABASE_URLis correct - Check
NEXT_PUBLIC_SUPABASE_ANON_KEYis the anon key (not service role) - Ensure no extra whitespace in environment variables
- Check the
handle_new_usertrigger exists - Manually create profile:
INSERT INTO profiles (id, email) SELECT id, email FROM auth.users WHERE id = 'user-uuid';
- Ensure
auth.uid()is being called (user is authenticated) - Check policy conditions match your data structure
- Test with service role to bypass RLS and verify data exists
- Enable RLS on the table:
ALTER TABLE tablename ENABLE ROW LEVEL SECURITY; - Create appropriate policies for the operation (SELECT, INSERT, UPDATE, DELETE)
- Ensure you copied the
service_rolekey (not anon) - Check it's in
.env.prod(not.env) - Verify the key hasn't been rotated in Supabase Dashboard
- Never expose service role key - Only use in server-side code
- Enable RLS on all tables - Default deny all access
- Use RPC functions for sensitive operations - Better control and logging
- Rotate keys if compromised - Regenerate in Supabase Dashboard
- Monitor auth logs - Watch for suspicious activity
- Use strong database password - Generated during project creation
- Enable MFA for Supabase account - Protect your dashboard access
Supabase now offers two API key systems. The new publishable and secret keys are recommended for all new projects and provide significant security and performance improvements.
| Type | Format | Privileges | Usage |
|---|---|---|---|
| Publishable key | sb_publishable_... |
Low | Safe for client-side: web pages, mobile apps, CLIs |
| Secret key | sb_secret_... |
Elevated | Server-side ONLY: API routes, Edge Functions, webhooks |
anon (legacy) |
JWT | Low | Same as publishable key |
service_role (legacy) |
JWT | Elevated | Same as secret key |
| Benefit | Legacy (anon/service_role) |
New (publishable/secret) |
|---|---|---|
| Performance | JWT validation requires Auth server call | Local JWT verification (faster) |
| Rotation | Rotating JWT secret causes downtime | Zero-downtime rotation |
| Security | All keys tied to single JWT secret | Independent key management |
| Revocation | Requires careful coordination | Instant, reversible revocation |
- Independent Rotation - Secret keys can be rotated without affecting publishable keys
- Browser Protection - Secret keys automatically reject browser requests (401 Unauthorized)
- Multiple Secret Keys - Create separate secret keys for different backend components
- No JWT Secret Exposure - Private keys cannot be extracted from Supabase
- Go to Settings → API in the Supabase Dashboard
- Find the new publishable and secret keys (or create them if not yet available)
- Update your environment variables:
# .env (public)
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=sb_publishable_xxx # New format
# .env.prod (server-side)
SUPABASE_SERVICE_ROLE_KEY=sb_secret_xxx # New format- Update code to use new auth patterns (optional but recommended):
// Old way (requires server call)
const {
data: { user },
} = await supabase.auth.getUser();
// New way (local verification with asymmetric keys)
const {
data: { claims },
} = await supabase.auth.getClaims();- Test your application with the new keys
- Once confirmed working, disable the legacy keys in the dashboard
Both key systems work simultaneously. You can migrate at your own pace:
- Legacy keys (
anon,service_role) remain functional - New keys available now in the Supabase Dashboard
- Recommended: Use new keys for better security and performance
- Edge Functions: Currently only support JWT verification via legacy keys. Use
--no-verify-jwtflag with new keys and implement your own verification - CLI/Self-hosting: Publishable and secret keys are only available on the hosted platform
- Supabase Docs: https://supabase.com/docs
- Supabase Discord: https://discord.supabase.com
- GitHub Issues: Report project-specific issues