Supabase Overview

リン (linh)
Goalist Blog
Published in
7 min readFeb 29, 2024

I. What is Supabase

Last time, we had a brief look on BaaS (Backend as a Service). So, today, i’d like to introduce Supabase as a BaaS example.
If you go to their site, you’ll see a banner that said:

“Build in a weekend.
Scale to millions”

They actually mean it. I’m not very sure about the “scale to millions” part, but it’s definitely doable building something over the weekend with Supabase.

II. Features

Features or “Products” (as Supabase call in their documents) include Database, Authentication, Storage, AI & Vectors, Realtime and Edge Functions.
Since it’s an overview, i’m not going to go through all of them, and only focus on the aspects that all backends need, which are API, database and authentication. But don’t worry, their docs are well written and clear, if you need to implement other features, check out their official document.

Using BaaS means that you have no backend code to maintain, instead, everything is in a dashboard, from adding table to setting up security.

1. Database

Every Supabase project comes with a full Postgres database, a free and open source database which is considered one of the world’s most stable and advanced databases.

Each table in database is stored as a form of spreasheet so it’s easy to use, to edit, even to adjust relationship between tables.
Supabase allows us to enable Row-level security (RLS, a type of security that lets you filter data and enables access to specific rows in a table based on qualifying user conditions) with a click.

2. API

Supabase provides a RESTful API using PostgREST. This is a very thin API layer on top of Postgres. It exposes everything you need from a CRUD API at the URL.

API docs is auto-generated for each table, and types can be generated with Supabase CLI or again, with a click.

3. Authentication and Authorization

Supabase allows you to authenticate in various ways:

  • Password-based methods such as email or phone and password
  • Passwordless methods such as sending a magiclink or one-time password (OTP)
  • OAuth social providers
  • SAML SSO

Then, we can authorize users with row-level security.

III. Implementation

As always, i’ll use NextJs as an example but you can get a quick start with your favorite framework and language.

1. Setting up

  • Step 1: Signup for a Supabase account and login
    https://supabase.com/dashboard/sign-up
  • Step 2: Create new project
  • Step 3a (from scratch): If you made up your mind and decided to use Supabase from the beginning, then use the command below:
npx create-next-app -e with-supabase
  • Step 3b (not from scratch): If you’ve already installed nextjs and are working on your frontend. Add these in your current project:
npm install @supabase/supabase-js @supabase/ssr

* Make sure to have client.ts, server.ts, middleware.ts files in your /src/utils/supabase folder. Content of these files can be refered here. And also route.tsfile in your src/app/auth/callback folder as below.

import { createClient } from "@/utils/supabase/server";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
// The `/auth/callback` route is required for the server-side auth flow implemented
// by the SSR package. It exchanges an auth code for the user's session.
// https://supabase.com/docs/guides/auth/server-side/nextjs
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
const origin = requestUrl.origin;
if (code) {
const supabase = createClient();
await supabase.auth.exchangeCodeForSession(code);
}
// URL to redirect to after sign up process completes
return NextResponse.redirect(`${origin}/protected`);
}
  • Step 4: add .local.env to your project
NEXT_PUBLIC_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>

SUBSTITUTE_SUPABASE_URL is your project URL, and SUBSTITUTE_SUPABASE_ANON_KEY is project API key. You can find them in Project setting > API section

2. Database

We can create new tables and datas using “Table Editor” (manually add table, colums and datas) and “SQL Editor” (normal SQL scripts).

Since we haven’t implemented authorization, be sure that RLS is disabled.

3. API

Head over to API Docs on your Dashboard side menu.
In Tables and Views section, you will see all your table there, select a table and you'll find api docs that help you query data from that selected table.

To generate types and download types, select Introduction and click on generate button.

Basic CRUD operations work perfectly fine, and we can also listen to changes of database. But in case you have a complex query case, you can add your own query functions using Query Editor, or go to Database and add your functions. Then go back to API Docs, you'll see your new function's document under Stored Procedures section.

To use API with type in your project is simple, here’s an example of getting all notes from Note database that we created at earlier.

"use client";
import { Tables } from "@/app/types/supabase";
import { createClient } from "@/utils/supabase/client";
import { useState } from "react";

export default function Test() {
const supabase = createClient();
const [notes, setNotes] = useState<Tables<"notes">[]>([]);

supabase
.from("notes")
.select()
.then((res) => res.data && setNotes(res.data));

return (
<div>
Notes:<br /><br />
<ul>
{notes.map((n, nId) => (
<li key={nId}>{n.id}. {n.title}</li>
))}
</ul>
</div>
);
}

Output:

*Please be noted that if your component is server side render, createClient should be imported from @/utils/supabase/server

Just follow the API Docs to get, post, update, delete, subsctibe to changes, and to call your custom query functions.

If you get any error, recheck your .env and RLS status of your table.

4. Authentication and Authorization

Authentication should normally be implemented first, but this part is easy with Supabase, so it doesn’t matter much.

Navigating to Authentication > Providers, you will see that email has been enabled by default, but there are also other Auth Providers that you can enable.

The API for signup looks like this:

// this is example on SSR. API on CSR is similar
const signUp = async (formData: FormData) => {
const origin = headers().get("origin");
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const supabase = createClient();
const { error } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${origin}/auth/callback`,
},
});
if (error) {
return redirect("/login?message=Could not authenticate user");
}
return redirect("/login?message=Check email to continue sign in process");
};

The signup flow is nothing far from normal:

  • When you sign up, a confirmation link will be sent to your email
  • The link in your email contains a code, which redirect user to page /auth/callback and code will be checked to make sure it's the correct user
  • If it’s ok, you will then be redirected to your protected route.

After successfully registered, next login will be a simple api call.

// this is example on SSR. API on CSR is similar
const signIn = async (formData: FormData) => {
"use server";
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const supabase = createClient();
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return redirect("/login?message=Could not authenticate user");
}
return redirect("/protected");
};

When logging out, we also need to call api.

// this is example on SSR. API on CSR is similar
const signOut = async () => {
"use server";
const supabase = createClient();
await supabase.auth.signOut();
return redirect("/login");
};

Et, voilà!
Your app is done, just deploy your frontend and replace your domain on supabase with your deployed domain, and you app is good to go.

I guess now you know why their banner said “Build in a weekend”. Above are enough to build an app, but there are a lot more, if you have a chance, i believe it’s worth a try. Thank you for reading this far. Hope to see you in another blog.

--

--

リン (linh)
Goalist Blog

A career-changed-non-tech-background point of view.