About the author:
Daniel is co-founder and CTO at Aqarios GmbH. He holds a M.Sc. in Computer Science from LMU Munich, and has published papers in reinforcement learning and quantum computing. He writes about technical topics in quantum computing and startups.
jrnl · home about list my companies

# Extending supabase with your own backend - its supa easy!

In recent years lowcode solutions and tech services have become increasingly useful in my opinion. Firebase has become an essential of tech MVPs, and now there is a new kid on the block called supabase. Tested it, loved it. Of course, most of the time you need more than a bit of CRUD, so I will show you in this post how to extend supabase with your own backend. It's actually supa easy. (lol)

First off, what is supabase? I'd say in one sentence: supabase is backend as a service. It runs on PostgreSQL, has an extensive online table editor (cf. picture below), logging, backups, replication, and easy file hosting (akin to Amazon S3).

The best part is how easily plug&play their integration is into your frontend. Check out the example below, that is for uploading a file in React. You can also interact in a very SQL-like fashion with the database from React. Can you believe this?!

// Uploading a file
const file = event.target.files[0]
const fileExt = file.name.split('.').pop()
const fileName = `${Math.random()}.${fileExt}`
const filePath = `${fileName}`

let { error: uploadError } = await supabase.storage
  .upload(filePath, file)
// Selecting data
let resp = await supabase
  .eq('account_group_id', id_)
  .order('id', { ascending: false })
// Upsert :D
let resp = await supabase.from('invitedusers').upsert({
  "id": invitedNames[idx].id,
  "user_email": invitedNames[idx].user_email,
  "account_group_id": resp.data[0].id,
  "role": invitedNames[idx].role

One of the coolest features is the large support for authentification (logging in with ALL kinds of socials, check it out below), and again, with extremely easy integration in your frontend. Amazing.

const { user, session, error } = await supabase.auth.signInWithPassword({
  email: email,
  password: password,

const { user, session, error } = await supabase.auth.signInWithOAuth({
  provider: 'google',

So now onto the main part - extending supabase with your own backend. There are two elements to this as far as I see it. First, interacting with the database in general - thats supa easy. ;)

Go to your project settings, then to the API tab, and copy your project url and key (cf. picture below).

You can then use those (the url and the key) and simply talk with the database, as seen below.

from supabase import Client
from supabase import create_client

supabase = create_client(url, key)
data = supabase.table('accountgroups').select("*").execute()
for item in data:

The second element is user-authenticated interaction with the database. Say you want to generate an excel sheet for a user, IF they are logged in. How to check? See below. Note that you can get the JWT in the frontend easily, it's a field in your session object (session.access_token). If you want to know how to set this up in React, go to the end of the post.

supabase = create_client(url, key)

# Check if logged in
    return {"error": "not logged in"}

This wraps it up for now. I am now an advocate for Flutterflow and supabase! If you want to know more, check out my Flutterflow post.

Getting the session in the frontend.

Here is how this is set up, basically in the router we get the current session and pass it to all our pages that need it. In the login page we directly interact with supabase.auth, and this gets immediately reflected in our router, and thus passed to all pages.

const RouterDOM = () => {
    const [session, setSession] = useState(null)

    useEffect(() => {
      supabase.auth.getSession().then(({ data: { session } }) => {

      supabase.auth.onAuthStateChange((_event, session) => {
    }, [])

    return (
{!session ? (
                <Route exact path="/"><Login /></Route>
                <Route exact path="/new"><CreateAccount /></Route>
) : (
                <Route exact path="/"><Home session={session} /></Route>
                <Route exact path="/login"><Login /></Route>
                <Route exact path="/new"><CreateAccount /></Route>
                <Route exact path="/home"><Home /></Route>
// ...

We can then use the session object to pass the JWT to the backend like so:

var form = new FormData();
form.append("user_id", session.user.id);
form.append("jwt", session.access_token);

return fetch(IP + 'create', {
  method: 'POST',
  body: form,
  mode: "cors",
  credentials: "include",
}).then((resp) => {
  return resp.json().then((data) => {
    return data;
Published on