DEV Community

Cover image for Supabase Subscriptions Just Got Easier
Jonathan Gamble
Jonathan Gamble

Posted on • Edited on • Originally published at code.build

Supabase Subscriptions Just Got Easier

Channels

For the moment, subscribing to realtime data in Supabase is very limited, and not easy to use. I personally believe the channels features is unnecessary and a waste of the developers time... for now. Let's not add new feature modules until the current features are adequate... capiche?

(Keep reading for package information...)

If you come from Firebase, you will be very disappointed in the way that you subscribe to realtime data. This is the same for onAuthStateChange and for channels. There are a few problems here.

  1. You have to get the data first, as the Subscription does not return the current data beforehand.
  2. You have to watch each type of change "INSERT, UPDATE, DELETE," in order to see the changes. You have to manually update accordingly in each case.
  3. Only the current change is returned, not the whole data.
  4. The UI is incredibly over-engineered and counterintuitive. Just figuring out how it works takes you at least an hour without examples.
  5. There is a few second delay when starting the subscriptions.
  6. There is only one filter you can use: eq.
  7. There is no way to limit the results.
  8. Perhaps the most important, you cannot use Views with Supabase Channels.
  9. When a group of data is inserted, it doesn't return in bulk, but individually.
  10. There are no optimistic updates, nor persistent offline data capabilities.

Problems 1 - 4 - Clean Code

I cannot help with the limitations of Supabase, but I did write a package that makes dealing with Subscriptions way easier.

Problems 5 - 9

These are the current limitations of Supabase. Don't get me wrong, I LOVE SUPABASE, and I am currently using it on this blog: Code.Build. It just seems to me these are problems on the backburner and not at the top of the list to fix. Subscriptions to realtime data is incredibly important for a lot of people. Let's get this up-to-par please. I wrote a list of issues a while back. I finally decided to fix what I could.

This is just not good enough:

supabaseClient
  .channel('any_string_you_want')
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'movies',
    },
    (payload) => {
      console.log(payload)
    }
  )
  .subscribe()
Enter fullscreen mode Exit fullscreen mode

Problem 10 - Offline & Optimistic

Okay, so that last one is doable, and someone is working on the caching right now with supabase-cache-helpers.

I also wrote an app to show you how you can do optimistic updates. Basically, you just create an array of your data, and change that array before the subscriptions returns. This is how Firebase's subscriptions are extremally fast. I may integrate this later into j-supabase.

You can also see an example realtime todo app I build with subscriptions and optimistic updates:

j-supabase

So, I created a simple tree-shakable package. I plan on adding more cool stuff to it later.

Authentication

First thing is first. Install the package:

npm i j-supabase
Enter fullscreen mode Exit fullscreen mode

Make sure you have the latest version of Supabase SDK V2:

npm i @supabase/supabase-js
Enter fullscreen mode Exit fullscreen mode

Authentication now works as expected like it does in Firebase:

import { authUser, authSession, realtime } from 'j-supabase';

// user
const unsubscribe = authUser(supabase)
  .subscribe(user => console.log(user));

// session
const unsubscribe = authSession(supabase)
  .subscribe(session => console.log(session));
Enter fullscreen mode Exit fullscreen mode

The current data is returned, and you can easily get to the variables without navigating a sub-tree of objects. You can see how it was done before in my previous article.

Realtime Data

You can get the realtime data as you would expect, the Supabase way:

// subscribe to a table
const unsubscribe = realtime<Todo>(supabase)
  .from('todos')
  .subscribe(snap => console.log(snap));

// use the one `eq` filter
const unsubscribe = realtime<Todo>(supabase)
  .from('todos')
  .eq('uid', uid)
  .subscribe(snap => console.log(snap));
Enter fullscreen mode Exit fullscreen mode

I do have two optional inputs:

idField

Just in case your primary key is not id:

const unsubscribe = realtime<Todo>(supabase, {
    idField: 'user_id'
  })
  .from('todos')
  .eq('uid', uid)
  .subscribe(snap => console.log(snap));
Enter fullscreen mode Exit fullscreen mode

schema

You must set your async schema when you declare your use createClient, but you can set your subscriptions schema this way:

const unsubscribe = realtime<Todo>(supabase, {
    schema: 'marketing'
  })
  .from('todos')
  .eq('uid', uid)
  .subscribe(snap => console.log(snap));
Enter fullscreen mode Exit fullscreen mode

This package is very easy, very clean (I do not use any dependencies), and very useful!

That is pretty much all Supabase can do... for the moment... but I hope to see new filters soon, and hopefully subscribable Views in the near future..

Possible todo list:

  • auto-resubscribe - while Supabase does automatically re-subscribe, you lose your data. This would keep it.
  • optimistic updates - Optimistic updates would be impossible for all situations, but I may add upsert, insert, update, and delete functions in this package to catch optimistic updates from the subscribed table. TBD.

Hope this helps someone,

J

Top comments (0)