Now that we understand the fundamentals of Supabase realtime subscriptions, let's put that knowledge into practice by building a simple, yet powerful, collaborative to-do application. In this app, multiple users can view and update the same to-do list in real-time. Any change made by one user will instantly be reflected on the screens of all other connected users.
Our collaborative to-do app will consist of a basic frontend that displays a list of to-do items. Each item will have a checkbox to mark it as complete and a button to delete it. The magic happens in how these actions are synchronized across all connected clients using Supabase realtime.
First, let's set up our Supabase project and create a simple table to store our to-do items. We'll need a table named todos with columns like id (UUID, primary key), task (text), and is_complete (boolean, default false). Crucially, we need to enable real-time subscriptions for this table.
CREATE TABLE public.todos (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
task text NOT NULL,
is_complete boolean DEFAULT false,
PRIMARY KEY (id)
);With our table in place, let's consider the frontend implementation. We'll use JavaScript to interact with Supabase. The core components will be fetching the initial list of to-dos, subscribing to realtime changes, and handling user interactions like adding, toggling completion, and deleting to-dos.
Here's how we'll initialize the Supabase client and fetch the initial list of to-dos. This is standard practice before we can leverage realtime updates.
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = 'YOUR_SUPABASE_URL'
const supabaseAnonKey = 'YOUR_SUPABASE_ANON_KEY'
const supabase = createClient(supabaseUrl, supabaseAnonKey)
async function fetchTodos() {
const { data, error } = await supabase.from('todos').select('*')
if (error) console.error('Error fetching todos:', error)
else {
// Render todos to the UI
console.log('Initial todos:', data)
}
}The real magic happens when we subscribe to changes in the todos table. We'll use supabase.channel() and on() to listen for INSERT, UPDATE, and DELETE events. When an event occurs, we'll update our UI accordingly.
const todosSubscription = supabase.channel('custom-all-channel')
.on('postgres_changes', {
event: '*', // Listen for all events
schema: 'public',
table: 'todos'
}, (payload) => {
console.log('Change received!', payload)
// Handle INSERT, UPDATE, DELETE events here to update the UI
if (payload.new && payload.eventType === 'INSERT') {
// Add new todo to the UI
} else if (payload.new && payload.eventType === 'UPDATE') {
// Update existing todo in the UI
} else if (payload.old && payload.eventType === 'DELETE') {
// Remove todo from the UI
}
})
.subscribe()
// Remember to unsubscribe when the component unmounts
// todosSubscription.unsubscribe()Let's outline the flow of a user marking a to-do item as complete. This involves a frontend action triggering a database update, which then propagates via the realtime subscription.
sequenceDiagram
participant User
participant Frontend
participant Supabase
User->>Frontend: Clicks 'Complete' checkbox
Frontend->>Supabase: UPDATE todos SET is_complete = true WHERE id = 'todo-id'
Supabase->>Frontend: Acknowledges update
Supabase->>OtherFrontends: Notifies of 'UPDATE' event for 'todo-id'
OtherFrontends->>Frontend: Receives 'UPDATE' event
Frontend->>Frontend: Updates UI for the completed to-do
Similarly, when a user adds a new to-do, the process is as follows. The frontend inserts the data, Supabase confirms, and then broadcasts the new item to all connected clients.
sequenceDiagram
participant User
participant Frontend
participant Supabase
User->>Frontend: Enters new to-do and clicks 'Add'
Frontend->>Supabase: INSERT INTO todos (task) VALUES ('New Task')
Supabase->>Frontend: Acknowledges insertion and returns new todo data
Supabase->>OtherFrontends: Notifies of 'INSERT' event with new todo data
OtherFrontends->>Frontend: Receives 'INSERT' event
Frontend->>Frontend: Adds the new to-do to the UI
And when a to-do is deleted, the flow is straightforward: the frontend deletes, Supabase confirms and broadcasts, and other clients remove the item.
sequenceDiagram
participant User
participant Frontend
participant Supabase
User->>Frontend: Clicks 'Delete' button for a to-do
Frontend->>Supabase: DELETE FROM todos WHERE id = 'todo-id'
Supabase->>Frontend: Acknowledges deletion
Supabase->>OtherFrontends: Notifies of 'DELETE' event for 'todo-id'
OtherFrontends->>Frontend: Receives 'DELETE' event
Frontend->>Frontend: Removes the deleted to-do from the UI
By implementing these realtime subscriptions, our to-do app becomes truly collaborative. Any action taken by one user instantly updates the state for all other users, creating a seamless and dynamic user experience without the need for manual refreshes or complex polling mechanisms. This is the power of Supabase realtime in action!