Supabase Client
JetShip provides a robust data fetching layer using Supabase, with optimized implementations for both client and server-side operations. This guide explains how to effectively use Supabase in your JetShip application.
Client Setup
JetShip provides two main ways to interact with Supabase:
- Browser Client (Client Components)
- Server Client (Server Components & API Routes)
Browser Client
For client-side operations, use the browser client:
import { createClient } from '@repo/supabase/client'
// In your component
const supabase = createClient()
Example usage in a React component:
'use client'
import { useState, useEffect } from 'react'
import { createClient } from '@repo/supabase/client'
export default function ProfileComponent() {
const [profile, setProfile] = useState(null)
const supabase = createClient()
useEffect(() => {
async function fetchProfile() {
const { data, error } = await supabase
.from('profiles')
.select('*')
.single()
if (error) {
console.error('Error fetching profile:', error)
return
}
setProfile(data)
}
fetchProfile()
}, [])
return <div>{/* Your JSX here */}</div>
}
Server Client
For server-side operations, use the server client:
import { createClient } from '@repo/supabase/server'
// In your Server Component or API Route
const supabase = await createClient()
Example usage in a Server Component:
import { createClient } from '@repo/supabase/server'
export default async function ServerComponent() {
const supabase = await createClient()
const { data: posts } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
return <div>{/* Your JSX here */}</div>
}
Service Role Client
The "service_role" is a predefined Postgres role with elevated privileges, designed to perform various administrative and service-related tasks. It can bypass Row Level Security, so it should only be used on a private server.
Never expose the service_role
key in a browser or anywhere where a user can see it.
For admin operations that require elevated privileges:
import { createServiceRoleClient } from '@repo/supabase/server'
// Use with caution - has admin privileges
const supabase = createServiceRoleClient()
Best Practices
1. Choose the Right Client
-
Use
@repo/supabase/client
for:- Client-side data fetching
- Real-time subscriptions
- User authentication flows
-
Use
@repo/supabase/server
for:- Server Components
- API Routes
- Server Actions
- Middleware
2. Error Handling
Always implement proper error handling:
try {
const { data, error } = await supabase.from('your_table').select('*')
if (error) {
throw error
}
// Process data
} catch (error) {
console.error('Database error:', error)
// Handle error appropriately
}
Common Patterns
1. Data Fetching with RLS
When using Row Level Security (RLS):
// Fetch user's own data
const { data: userPosts } = await supabase.from('posts').select('*')
// RLS will automatically filter based on auth.uid()
2. Optimistic Updates
Implement optimistic updates for better UX:
// Current data
const [items, setItems] = useState([])
// Optimistic update
const addItem = async newItem => {
// Update UI immediately
setItems(prev => [...prev, newItem])
// Perform actual update
const { error } = await supabase.from('items').insert(newItem)
if (error) {
// Revert on error
setItems(prev => prev.filter(item => item.id !== newItem.id))
console.error('Failed to add item:', error)
}
}
3. Batch Operations
For multiple operations:
const { error } = await supabase.rpc('your_batch_function', {
items: [
/* your items */
]
})