- Learn
- Stack Essentials
- Supabase
- Setup & Configuration
Configure Supabase client for Next.js with server and client components, middleware, and TypeScript types.
Setup & Configuration
Set up Supabase in your Next.js project with proper client configuration for both server and client components.
Create Supabase Project
1. Sign Up / Login
Visit supabase.com and create an account.
2. Create New Project
Dashboard → New Project
Name: my-app
Database Password: [generate strong password]
Region: [choose closest]
Save your database password—you'll need it for direct connections.
3. Get API Credentials
From Settings → API:
- Project URL:
https://xxxxx.supabase.co - Anon Key: Public key for client-side (safe to expose)
- Service Role Key: Admin key (keep secret!)
Install Dependencies
npm install @supabase/supabase-js @supabase/ssr
@supabase/ssr provides helpers for Server-Side Rendering frameworks like Next.js.
Environment Variables
Create .env.local:
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
The NEXT_PUBLIC_ prefix makes these available in browser code.
Never expose Service Role Key:
# Only if needed for server-side admin operations
SUPABASE_SERVICE_ROLE_KEY=eyJ... # No NEXT_PUBLIC_ prefix!
Client Configuration
Browser Client
For Client Components:
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Usage:
'use client'
import { createClient } from '@/lib/supabase/client'
export function UserProfile() {
const supabase = createClient()
async function loadUser() {
const { data: { user } } = await supabase.auth.getUser()
// ...
}
}
Server Client
For Server Components and Route Handlers:
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// Called from Server Component
}
},
},
}
)
}
Usage:
// app/dashboard/page.tsx
import { createClient } from '@/lib/supabase/server'
export default async function Dashboard() {
const supabase = await createClient()
const { data: posts } = await supabase
.from('posts')
.select('*')
return <PostList posts={posts} />
}
Middleware Client
For authentication middleware:
// lib/supabase/middleware.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// Refresh session if expired
await supabase.auth.getUser()
return supabaseResponse
}
// middleware.ts
import { type NextRequest } from 'next/server'
import { updateSession } from '@/lib/supabase/middleware'
export async function middleware(request: NextRequest) {
return await updateSession(request)
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
TypeScript Types
Generate Types
Install Supabase CLI:
npm install -D supabase
Generate types from your database:
npx supabase gen types typescript --project-id xxxxx > types/supabase.ts
Or add to package.json:
{
"scripts": {
"types": "supabase gen types typescript --project-id xxxxx > types/supabase.ts"
}
}
Generated Types Example
// types/supabase.ts
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json | undefined }
| Json[]
export interface Database {
public: {
Tables: {
posts: {
Row: {
id: string
title: string
content: string | null
user_id: string
created_at: string
}
Insert: {
id?: string
title: string
content?: string | null
user_id: string
created_at?: string
}
Update: {
id?: string
title?: string
content?: string | null
user_id?: string
created_at?: string
}
}
// ... more tables
}
}
}
Using Types
Update client files:
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
import { Database } from '@/types/supabase'
export function createClient() {
return createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Now queries are fully typed:
const supabase = createClient()
// TypeScript knows posts structure
const { data: posts } = await supabase
.from('posts')
.select('*')
// data is typed as Post[] | null
posts?.forEach(post => {
console.log(post.title) // TypeScript knows this exists
})
Project Structure
Complete setup:
project/
├── lib/
│ └── supabase/
│ ├── client.ts # Browser client
│ ├── server.ts # Server client
│ └── middleware.ts # Middleware helpers
├── types/
│ └── supabase.ts # Generated database types
├── middleware.ts # Auth middleware
├── .env.local # Environment variables
└── package.json
Testing Connection
Create a test page:
// app/test-supabase/page.tsx
import { createClient } from '@/lib/supabase/server'
export default async function TestPage() {
const supabase = await createClient()
// Test connection
const { data, error } = await supabase
.from('posts')
.select('count')
.limit(1)
if (error) {
return <div>Error: {error.message}</div>
}
return <div>Supabase connected successfully!</div>
}
Common Configuration Options
Custom Fetch
createBrowserClient(url, key, {
global: {
fetch: customFetch,
},
})
Auth Configuration
createBrowserClient(url, key, {
auth: {
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
})
Realtime Configuration
createBrowserClient(url, key, {
realtime: {
params: {
eventsPerSecond: 10,
},
},
})
AI Tool Integration
Lovable Setup
Lovable auto-configures Supabase:
- Click Supabase in settings
- Enter project URL and anon key
- Lovable generates client files automatically
Bolt.new Setup
Bolt creates Supabase config when you ask:
"Add Supabase to this project for user authentication"
Claude Code Setup
"Set up Supabase with proper Next.js 14 configuration
including server client, client client, middleware,
and TypeScript types generation"
Environment Variables Checklist
| Variable | Required | Where Used |
|---|---|---|
| NEXT_PUBLIC_SUPABASE_URL | Yes | Client & Server |
| NEXT_PUBLIC_SUPABASE_ANON_KEY | Yes | Client & Server |
| SUPABASE_SERVICE_ROLE_KEY | No | Server admin only |
Summary
- Browser client: For Client Components
- Server client: For Server Components and API routes
- Middleware: For auth session refresh
- Types: Generate from database schema
- Environment: Use NEXT_PUBLIC_ for client-safe vars
Next Steps
Learn to create tables, run queries, and manage data with Supabase database.