Skip to main content

Modern Web Architecture Without a Backend — Using Supabase

· 7 min read
Yiming
Co-founder of ZenStack

Cover Image

Backend development is difficult for people who come entirely from a frontend background. The languages, frameworks, and tools differ, but more importantly, the frontend and backend systems have very different principles. Fortunately, a new generation of libraries and services is trying to fill the gap and simplify coding a backend by …, not coding it at all.

To code a backend or not to code

In this post, let’s talk about Supabase - what it is, how it works, and what kind of scenarios it fits best.


This post is part of a series about libraries and services that simplifies the construction of the backend of web apps. You can find the full series here:


What’s Supabase?

Supabase is an open-source cloud service, and you can understand it as one of the following two things:

  • A PostgreSQL hoster

    It allows you to create fresh Postgres instances with just a few clicks and use it in your application’s backend. It also provides a built-in SQL editor and a data browser for you to manage the database inside a browser.

  • A BaaS (Backend-as-a-Service)

    It offers a comprehensive set of services, including auth, database access control, blob storage, edge functions, etc. The capabilities allow you to use Supabase as your backend instead of implementing one by yourself.

In this article, let's explore Supabase in the context of BaaS.

Feature Package

Supabase provides five essential services:

  1. Auth authenticates users
  2. Database serves a standard PostgreSQL
  3. Realtime supports broadcasting messages and states to clients
  4. Edge Functions allows execution of custom typescript code
  5. Storage stores and serves files.

Each of these services can be used separately, but you'll likely use Auth together with everything else so that you can authorize users' requests.

Auth

The Auth service deals with user signup and authentication. It supports email, magic links, and a wide range of social login methods. If you're familiar with NextAuth, you can think of Supabase's Auth module as a reimplementation of NextAuth without the hard dependency on Next.js. What's neat about the Auth service is that, since it has a buddy Database service, it has a natural place to store user data, so you don't need to configure storage for it.

Auth service is at the centre of Superbase's architecture. It verifies a user's identity but doesn't control what she can or cannot do. The latter is called "authorization" and is handled by each of the other four services, respectively, but they rely on the verified identity to do that.

Database

Supabase sets itself apart from other BaaS with its strong heritage from PostgreSQL, and the Database service is proof of that. Database service directly inherited all the bells and whistles of Postgres - tables, views, functions, row-level security (RLS), etc.

The most significant addition Supabase added to Postgres is the "serverless APIs". Every table, view and function is automatically mapped to a RESTful and a GraphQL (still Beta) API. These APIs allow you to conduct CRUD operations directly from the frontend. But, of course, you must be immediately alarmed: what about security? Supabase delegates that entirely to PostgreSQL's RLS. You're supposed to use the "Auth" service to authenticate users and set up RLS to guard against unauthorized operations. A typical RLS looks like this:


# Simple RLS for blog posts

# owner has full access to her own posts
CREATE POLICY post_owner_policy ON post
USING (owner = current_user);

# all users can read published posts
CREATE POLICY post_read_policy ON post FOR SELECT
USING (published = true);

The entire flow for an authorized request looks like:

Database auth flow

, and calling the database from the frontend looks like this:

// Initialize the JS client
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

// Make a request
const { data: todos, error } = await supabase.from('todos').select('*');

The overall idea is very similar to how PostgREST works. In fact, Supabase's RESTful layer is built with PostgREST. Please check out the following post if you're interested.

Modern Web Architecture Without a Backend — Using PostgREST

###Realtime

Realtime is a utility service for subscribing to 3 types of real-time events: "Broadcast" for pub-sub pattern, "Presence" for synchronizing user's online status, and "Postgres Changes" for listening to database changes.

Realtime scenarios

It's worth noting that if you've configured RLS in database tables, the database changes notifications also respect RLS policies, and clients only get the messages they're supposed to see.

Storage

Supabase's storage offering is similar to blob storage services from most other cloud providers: a simple bucket/folder/file structure. Although Storage is not part of the SQL database store, its access control is configured with Postgres RSL, but how?

The idea is that, although blobs are stored elsewhere, their metadata resides in the SQL database as regular tables. So when you use RLS to specify Storage access policies, you're actually setting it up for its metadata. When the Storage service processes a request, it first checks with the Postgres side to see if it is permitted.

Edge Functions

Edge Functions are custom Typescript codes that you can deploy to Supabase and let them run on edge nodes, responding to client requests. Edge Functions uses Deno at runtime, apparently for better security and faster cold start; so supposedly, the Typescript code needs to stay within the boundary of what's supported by Deno.

Edge Functions has a simple way of supporting authorization. The client sends over the JWT token received during authentication. The edge function code gets the user's identity (extracted from the token) as its input, so it can use that to check permissions. If the function accesses the database, it can also create a Postgres client with the authenticated user's context, so the database's RLS policies can work their magic.

Is It a Good Choice For Me?

As you've seen, Supabase's BaaS offering is comprehensive. The combination of its services should suffice for many web apps of low to medium complexity. However, you may want to weigh the following non-functional factors before making a decision:

  1. Are you OK with using a 3rd party service as your entire backend?

    Supabase is open source, and you should be able to host it yourself. Still, right now, documentation for self-hosting is limited, and I've never heard or read anyone doing self-hosting for serious applications.

  2. Are you comfortable with working with PostgreSQL a lot?

    Supabase has a strong lineage from Postgres. You'll find yourself at home if you know Postgres well and may suffer if not. Solid knowledge of Postgres is needed to use it well.

  3. Do you like the idea of writing business logic in SQL?

    PostgreSQL's RLS is a powerful tool. It works as a very reliable gatekeeper to keep your data safe. However, as you use it more, you'll inevitably get into a situation where a big chunk of your business logic is expressed in SQL. IMHO, SQL language was not optimally designed for that.

  4. How about your application's data model not staying with the code anymore?

    If you use Supabase as a BaaS, you don't use an ORM anymore. Instead, you use serverless APIs (RESTful or GraphQL). As a result, one of the major benefits of an ORM - a centralized data model of your entire application within the source code - is lost.

Wrap Up

Supabase is an excellent product that covers many aspects of a web application's backend needs. It may significantly shorten your time-to-market. I hope this article can help you see the upsides and downsides of using it and finally make a sound decision.

Share on
Comments
Feel free to ask questions, give feedback, or report issues.

Don't Spam


You can edit/delete your comments by going directly to the discussion, clicking on the 'comments' link below