PolarDB Supabase best practices: Build a web application
PolarDB Supabase is PolarDB for PostgreSQL's fully managed Supabase service. Centered around PolarDB for PostgreSQL as its core, it integrates and enhances key features, such as a Realtime database, RESTful APIs, GoTrue authentication, file storage, and log collection. This frees you from the complex parameter management and application O&M of Supabase and provides a flexible and high-performance backend solution. You can use PolarDB Supabase to quickly build modern applications, such as web applications, SaaS platforms, and AI-integrated applications.
This guide shows you how to use PolarDB Supabase to quickly build a meeting notes system.
Demo
When you open two browsers and join the same meeting, you will see information synchronize in real time across both. The core features of the meeting notes system include real-time collaborative editing, user presence management, file uploads and management, task tracking, activity logs, and a tagging system.
Core features
|
Feature |
Description |
|
Full database capabilities |
Supabase is built on PolarDB for PostgreSQL and offers a full suite of database features:
|
|
Realtime |
Uses PostgreSQL logical replication to enable real-time data synchronization:
|
|
Authentication |
A complete built-in authentication and authorization system:
|
|
Row-level security (RLS) |
Based on PostgreSQL row-level security policies:
|
|
Storage service |
File storage and management based on the PolarDB file system:
|
|
Edge functions |
Server-side functions based on Deno:
|
|
API (REST and GraphQL) |
Auto-generated API endpoints:
|
Build a meeting notes system
The meeting notes system primarily uses the following features:
|
Feature |
Description |
|
Stores data in tables for meetings, notes, tasks, and user status. |
|
|
Enables real-time collaboration by synchronizing note edits and user presence. |
|
|
Ensures data security by controlling user access. |
|
|
Manages files for uploading and downloading meeting materials. |
|
|
Manages user sign-in and sessions. |
Application tech stack
-
Frontend: Next.js 15 + React 18 + TypeScript.
-
Backend: PolarDB Supabase (PostgreSQL + authentication + Realtime + storage).
-
UI: Tailwind CSS + Radix UI.
-
State management: React Hooks + local state.
Database design
The database design for the meeting notes system includes tables for meetings, notes, user presence, tags, and tasks. Foreign key constraints ensure data consistency.
Realtime configuration
Enable Realtime
-- Enable the Realtime feature
ALTER PUBLICATION supabase_realtime ADD TABLE meetings;
ALTER PUBLICATION supabase_realtime ADD TABLE notes;
ALTER PUBLICATION supabase_realtime ADD TABLE user_presence;
ALTER PUBLICATION supabase_realtime ADD TABLE tags;
ALTER PUBLICATION supabase_realtime ADD TABLE tasks;
ALTER PUBLICATION supabase_realtime ADD TABLE meeting_activities;
ALTER PUBLICATION supabase_realtime ADD TABLE meeting_files;
Client-side subscriptions
// Create a custom hook to manage Realtime subscriptions
export function useRealtime(meetingId: string, callbacks: RealtimeCallbacks) {
const channelsRef = useRef<any[ ]>([ ])
const cleanup = useCallback(() => {
channelsRef.current.forEach((channel) => {
supabase.removeChannel(channel)
})
channelsRef.current = []
}, [])
useEffect(() => {
if (!meetingId) return
// Clean up previous connections
cleanup()
// Create multiple dedicated channels
const presenceChannel = supabase
.channel(`presence:${meetingId}`)
.on(
"postgres_changes",
{
event: "*",
schema: "public",
table: "user_presence",
filter: `meeting_id=eq.${meetingId}`,
},
(payload) => {
console.log("User presence change:", payload)
if (callbacks.onUserPresenceChange) {
loadOnlineUsers()
}
},
)
.subscribe()
// Save channel references for cleanup
channelsRef.current = [presenceChannel, /* other channels */]
}, [meetingId, callbacks])
return { cleanup }
}
Realtime subscription design
-
Feature isolation: Isolate features into separate channels by scenario (for example, presence, document collaboration, and task notifications) to reduce logical coupling.
-
Event filtering: Use the
filterparameter to scope events (for example, by specifying a meeting ID) to reduce redundant data transmission. -
Resource cleanup: When a component unmounts or the page changes, call
removeChannelto clean up all channel connections and release resources. -
Error handling: Monitor the status of subscription channels to implement retry or fallback mechanisms for exceptions such as disconnections and timeouts.
Security
Row-level security (RLS)
-- Enable RLS
ALTER TABLE meetings ENABLE ROW LEVEL SECURITY;
-- Create security policies
CREATE POLICY "Users can view all meetings" ON meetings
FOR SELECT USING (true);
CREATE POLICY "Users can create meetings" ON meetings
FOR INSERT WITH CHECK (true);
CREATE POLICY "Users can update their own meetings" ON meetings
FOR UPDATE USING (auth.uid() = created_by);
User authentication
const login = useCallback(async (email: string, password: string) => {
try {
const { data, error } = await supabase.auth.signInWithPassword({ email, password })
if (error) throw error
if (data.user) {
const userData = transformSupabaseUser(data.user)
setUser(userData)
localStorage.setItem("meeting_user", JSON.stringify(userData))
return { success: true, user: userData }
}
return { success: false, error: 'Sign-in failed' }
} catch (error: any) {
return { success: false, error: error.message || 'Sign-in failed' }
}
}, [])
const transformSupabaseUser = (supabaseUser: SupabaseUser): User => ({
id: supabaseUser.id,
email: supabaseUser.email || null,
name: supabaseUser.user_metadata?.name || supabaseUser.email?.split('@')[0] || 'User',
avatar_url: supabaseUser.user_metadata?.avatar_url || null,
created_at: supabaseUser.created_at,
is_anonymous: supabaseUser.user_metadata?.is_anonymous || false,
})
Client integration
Client
// 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)
// Type definition
export interface Meeting {
id: string
created_at: string
title: string
description: string | null
}
Environment variables
# Production environment variables
NEXT_PUBLIC_SUPABASE_URL=<YOUR_SUPABASE_PUBLIC_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<YOUR_SUPABASE_ANON_KEY>
Quick start
-
Download the sample project code: PolarDB-Supabase-App-Demo.
-
Prepare the runtime environment: Install
Node.jsandpnpmin your local environment.Note-
Node.js: Download and install it from the officialNode.jswebsite. -
pnpm: After you installNode.js, you can usenpmto install it globally. The command isnpm install -g pnpm.
-
-
Configure the environment: In the project's root directory, create a
.env.localfile and replace the following values with your PolarDB Supabase configuration.NoteOn the cluster's list page, click your Application ID to go to the application details page. The Topology and Configuration tabs contain the required configuration information.
-
<YOUR_SUPABASE_PUBLIC_URL>is the Public Endpoint of your application. -
<YOUR_SUPABASE_ANON_KEY>is the value of the application parametersecret.jwt.anonKey.
# Production environment variables NEXT_PUBLIC_SUPABASE_URL=<YOUR_SUPABASE_PUBLIC_URL> NEXT_PUBLIC_SUPABASE_ANON_KEY=<YOUR_SUPABASE_ANON_KEY> -
-
Initialize the database: In the
scriptsfolder in the project's root directory, locate the01-create-tables.sqlfile, and run the SQL in the SQL Editor on the right-side navigation bar of the Supabase Dashboard. -
Run the project: In the project's root directory, run the following commands to install dependencies and start the project. After the project starts, open
http://localhost:3000in your browser to access the application.pnpm install pnpm devAfter accessing the application, you will see the homepage for the Smart Meeting Notes System. The page displays four cards for core features: Real-time Collaboration, Smart Recording, Activity Tracking, and Task Management. On the left is a Create New Meeting form with a Meeting Title input box and a Meeting Description text area. On the right, the Experience Demo Meeting option allows you to join the most recently created meeting. A yellow banner at the top of the page reminds you to sign in or join anonymously before creating or joining a meeting.
Summary
This project demonstrates the following best practices for using PolarDB Supabase:
-
Database design: Implement a reasonable table structure, indexes, and constraints.
-
Realtime configuration: Separate concerns, manage resources, and handle errors.
-
Security: Define RLS policies, validate data, and implement user authentication.
-
Deployment and maintenance: Manage environment variables and database initialization.
Follow these best practices to build stable, secure, and high-performance PolarDB Supabase applications.