Realtime

Migrate to Broadcast Changes

How to migrate from Postgres Changes to Broadcast Changes


Postgres Changes has some limitations as your application scales. To continue broadcasting database changes to users as you scale, you can use Broadcast Changes.

Example application using Postgres Changes

Here we have a simple chess application that has a game id and we want to track whenever we have new moves happening for a given game id.

We store this information in a public.moves table and every time a new move is added to a given game_id we want to receive the changes in our connected Realtime client

In our client we will have our implementation to receive insert events with the usual code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const gameId = '4a8bbe89-f601-4414-bd47-8d0f7ab2a31a'const changes = supabase .channel('chess-moves') .on( 'postgres_changes', { event: 'INSERT', schema: 'public', table: 'moves', filter: `game_id=eq.${gameId}`, }, (payload) => console.log(payload) ) .subscribe() ...

Migrate to broadcast changes

To use Broadcast Changes, first familiarize yourself with the Broadcast Changes implementation.

Set up authorization

Broadcast Changes is private by default, using Realtime Authorization to control access. First, set up RLS policies to control user access to relevant messages:

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE POLICY "authenticated can listen to game moves"ON "realtime"."messages"FOR SELECTTO authenticatedUSING ( EXISTS ( SELECT 1 FROM game_users WHERE (SELECT auth.uid()) = user_id AND (select realtime.topic()) = 'games:' || game_id::text AND realtime.messages.extension = 'broadcast' ));

Set up trigger function

We need to define our trigger function to adapt to our use case and use the provided function realtime.broadcast_changes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE OR REPLACE FUNCTION public.broadcast_moves() RETURNS trigger AS $$BEGIN PERFORM realtime.broadcast_changes( 'games:' || NEW.game_id::text, -- topic TG_OP, -- event TG_OP, -- operation TG_TABLE_NAME, -- table TG_TABLE_SCHEMA, -- schema NEW, -- new record OLD -- old record ); RETURN NULL;END;$$ LANGUAGE plpgsql;

Setup trigger with created function

Now we need to setup our trigger to capture the events we want

1
2
3
4
CREATE TRIGGER chess_move_changesAFTER INSERT ON public.movesFOR EACH ROWEXECUTE FUNCTION public.broadcast_moves();

Listen to changes in client

Finally you can setup your client to listen for your events

1
2
3
4
5
6
7
8
9
10
11
12
const gameId = '4a8bbe89-f601-4414-bd47-8d0f7ab2a31a'await supabase.realtime.setAuth() // Needed for Realtime Authorizationconst changes = supabase .channel(`games:${gameId}`) .on( 'broadcast', { event: 'INSERT', }, (payload) => console.log(payload) ) .subscribe()