Skip to main content

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:

  1. Browser Client (Client Components)
  2. 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.

SECURITY

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 */
]
})