3 Things you should know BEFORE you start with Supabase

| 3 min read

Supabase is powerful and gaining much popularity. It’s a free and simple great alternative for Firebase. Even if you are not familiar with Firebase. Supabase has everything that you need. A database with real-time subscriptions, Authentication, and Storage.


Hi, I created Happy React. Service for adding reactions widgets on your website for free. I took care of performance and ease of using it. You can add reactions to your blog or documentation pages! It’s still in early access, let me know what you think about it and join the waiting list. Learn more on https://happyreact.com/


About Supabase

Supabase is built on top of open-source technologies. PostgreSQL, PostgREST, gotrue, and many many others. It’s a great idea. There are a lot of great libraries and technologies out there. Smart using established tools can be better than spending time reinventing the wheel.

The free plan has all functionality you need to build an application. The best part of that is you are not locked in. You can dump your database data and move it to another provider or custom server. There is no lock-in!

On top of all these features, there is a dashboard that lets you manage your project.

Supabase features

  • Auth
  • Storage
  • Database with real-time subscriptions

Supabase isn’t perfect but it’s powerful

What is the greatest strength is the biggest downfall. I repeat myself but Supabase is built on top of PostgreSQL. You need to know SQL, how to create queries and what PostgreSQL features have. Below are common gotchas about supabase you can have after starting.

Creating a view for complex queries

Supabase query builder is flexible. It can make basic selects, count rows, or join queries but you sometimes need more advanced usage of SQL. Postgres views can help you with that.

drop view if exists sold_products;
create
or replace VIEW public.sold_products AS (
  select
    DISTINCT ON (orders.product_id) product_id,
    products.name as name
  from
    orders
    inner join products on orders.product_id = products.id
);

This little snippet gets all orders and excludes repeated products so we get a list of all sold products.

⚠️ Note that view inherits permissions of creator. When you are creating it as admin it will have same permissions (bypass RLS) as admin. Create views with caution.

Adding cascading on delete

When you delete one record from a table and has a foreign key column on another table, you get an error. To delete a record and other records with foreign keys you need to add cascading delete.

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR
AS $$
DECLARE constraint_name varchar;
DECLARE reftable varchar;
DECLARE refcolumn varchar;
BEGIN
SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu
      ON tc.constraint_name = kcu.constraint_name
    JOIN information_schema.constraint_column_usage AS ccu
      ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' 
   AND tc.table_name= f_table AND kcu.column_name= f_column
INTO constraint_name, reftable, refcolumn;
EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' ||
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';';
RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column ||
 ' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options;
END;
$$ LANGUAGE plpgsql

Then you need to invoke a function like this:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE');

Row-level security

Protecting your database from unauthorized access is by using RLS. Those special “checks” are run before the query to make sure the person who is running it has the rights to do so.

You can reference uid() which will be replaced with a user id that is currently authorized. You can compare if the record that is currently processed belongs to the authorized user.

All values that you are sending using Supbase SDK will be replaced inside the RLS policy.

Next, you need to add RLS. A good idea is to keep it clean and create a Postgres function where you can pass all variables and make the query:

CREATE
OR REPLACE FUNCTION can_insert_post(_user_id uuid) RETURNS bool AS $$
SELECT EXISTS (
  SELECT
      1
    FROM
      posts
      INNER JOIN users ON users.id = posts.user_id
    GROUP BY
      users.id,
      posts.user_id
    HAVING
      COUNT(posts.id) < users.post_limit
      AND _user_id = posts.user_id
);
$$ LANGUAGE sql SECURITY DEFINER;

This function will check if the user doesn’t exceed the posts limit. Next, you need to reference it in RLS insert policy.

can_insert_post(uid())

Summary

Supabase is a great tool but it’s requiring some Postgres knowledge. Keep in mind that it is only the tip of the iceberg. The more you dive into Supabase you will need more Postgres knowledge.