Quick reference Supabase. Setup, authentication, database queries, real-time subscriptions, storage, Row Level Security, dan best practices untuk building modern apps.
Login atau daftar akun gratis untuk membaca cheat sheet ini.
# npm
npm install @supabase/supabase-js
# pnpm
pnpm add @supabase/supabase-js
# yarn
yarn add @supabase/supabase-js// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseAnonKey)# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc... # Server-side only// lib/supabase-server.ts
import { createClient } from '@supabase/supabase-js'
export const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!, // Bypass RLS
{
auth: {
autoRefreshToken:
// Get all rows
const { data, error } = await supabase
.from('posts')
.select('*')
// Select specific columns
// Insert single row
const { data, error } = await supabase
.from('posts')
.insert({ title: 'New Post', content: 'Hello World' })
.select
// Update by ID
const { data, error } = await supabase
.from('posts')
.update({ title: 'Updated Title' })
.eq('id', 1)
// Delete by ID
const { error } = await supabase
.from('posts')
.delete()
.eq('id', 1)
// Delete with conditions
const {
// Comparison operators
.eq('column', value) // Equal
.neq('column', value) // Not equal
.gt('column', value) // Greater than
.gte
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'password123',
options: {
data: {
full_name: 'John Doe',
age: 25
}
}
// Email & Password
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'password123'
})
// Magic Link (Passwordless)
const {
const { error } = await supabase.auth.signOut()// Get user from session
const { data: { user } } = await supabase.auth.getUser()
// Get session
const { data: { session } } = await supabase.auth.getSession()const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
console.log(event, session)
// events: 'SIGNED_IN', 'SIGNED_OUT', 'TOKEN_REFRESHED', etc.
}
)
// Cleanup
subscription.// Send reset email
const { data, error } = await supabase.auth.resetPasswordForEmail(
'user@example.com',
{
redirectTo: 'https://example.com/reset-password'
}
)
// Update password (after reset)
const { data
const { data, error } = await supabase.auth.updateUser({
data: {
full_name: 'Jane Doe',
avatar_url: 'https://example.com/avatar.jpg'
}
})// Subscribe to all changes
const subscription = supabase
.channel('posts-channel')
.on(
'postgres_changes',
{
event: '*', // '*', 'INSERT', 'UPDATE', 'DELETE'
schema: 'public',
const subscription = supabase
.channel('post-1')
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'posts',
filter:
const channel = supabase.channel('room-1')
// Listen to inserts
channel.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'messages' },
(payload)
// Send message
await channel.send({
type: 'broadcast',
event: 'cursor-pos',
payload: { x: 100, y: 200 }
})
// Listen to broadcast
channel.on('broadcast', { event: 'cursor-pos' }, (
const channel = supabase.channel('room-1')
// Track user presence
await channel.subscribe(async (status) => {
if (status
// Upload file
const { data, error } = await supabase.storage
.from('avatars')
.upload('user-1.png', file, {
cacheControl: '3600',
upsert: true
})
// Download file
const { data, error } = await supabase.storage
.from('avatars')
.download('user-1.png')
// Get public URL
const { data
const { data, error } = await supabase.storage
.from('avatars')
.list('public', {
limit: 100,
offset: 0,
sortBy: { column: 'name', order:
// Delete single file
const { data, error } = await supabase.storage
.from('avatars')
.remove(['user-1.png'])
// Delete multiple files
const { data, error
// Move file
const { data, error } = await supabase.storage
.from('avatars')
.move('old-path.png', 'new-path.png')
// Copy file
const { data,
-- Enable RLS on table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;-- Allow anyone to read
CREATE POLICY "Public posts are viewable by everyone"
ON posts FOR SELECT
USING (true);
-- Users can only see their own data
CREATE POLICY "Users can view own posts"
ON
// Use service role key to bypass RLS
import { createClient } from '@supabase/supabase-js'
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
)
// Now queries bypass RLS
const { data
# Using Supabase CLI
supabase functions new my-function// supabase/functions/my-function/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
serve(async (req) =>
supabase functions deploy my-function// From client
const { data, error } = await supabase.functions.invoke('my-function', {
body: { name: 'John' }
})
// With custom headers
const { data, error }
# Install Supabase CLI
npm install supabase --save-dev
# Login
npx supabase login
# Generate types
npx supabase gen types typescript --project-id YOUR_PROJECT_ID > types/database.ts// types/database.ts is auto-generated
import { Database } from '@/types/database'
// Create typed client
export const supabase = createClient<Database>(
supabaseUrl,
supabaseAnonKey
)
// Now queries are fully typed!
const { data
import { Database } from '@/types/database'
type Post = Database['public']['Tables']['posts']['Row']
type PostInsert = Database['public']['Tables'][
// app/dashboard/page.tsx
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
export default async function Dashboard() {
const supabase
import { useState, useEffect } from 'react'
function usePagination(table: string, pageSize = 10) {
const [data, setData] = useState
async function toggleTodo(id: string, isComplete: boolean) {
// Update UI immediately
setTodos(prev =>
prev.map(t => t.id ===
import { useState, useEffect } from 'react'
import { useDebounce } from 'use-debounce'
function SearchPosts() {
const [query, setQuery] = useState
select('id, title')).single() when fetching one rowcreated_at and updated_at timestamps# Supabase CLI
supabase init # Initialize Supabase project
supabase start # Start local Supabase
supabase stop # Stop local Supabase
supabase db reset # Reset local database
supabase db push # Push migrations to remote
supabase gen types