Skip to main content

Supabase JS


Bemi plugs into Supabase JS and PostgreSQL to track database changes automatically. It unlocks robust context-aware audit trails and time travel querying inside your application.

This package is a recommended Supabase JS integration, enabling you to pass application-specific context when performing database changes. This can include context such as the 'where' (API endpoint, worker, etc.), 'who' (user, cron job, etc.), and 'how' behind a change, thereby enriching the information captured by Bemi.

See this example repo as an Todo app example with Supabase JS that automatically tracks and contextualizes all changes.


  • Supabase JS


  1. Install the NPM package
npm install @bemi-db/supabase-js
  1. Generate a Supabase JS migration file to add a Database Function for passing application context with all data changes into PostgreSQL replication log
npx bemi migration new
  1. Run the Supabase JS migration
npx supabase migration up


Now you can easily specify custom application context that will be automatically passed with all data changes by calling setContext in your Supabase Edge Function:

import { setContext } from '[email protected]'
import { createClient } from '[email protected]'

Deno.serve(async (req) => {
const supabase = createClient(...)
const { method, url } = req
const endpoint = `/${url.split('/')[3]}`
const payload = method === 'POST' ? await req.json() : {}

// Customizable context
await setContext(supabase, { method, endpoint, payload })

// Your code that performs data changes

Application context:

  • Is bound to the current database session within an HTTP request.
  • Is used only with INSERT, UPDATE, DELETE SQL queries performed via Supabase JS.
  • Is passed directly into PG Write-Ahead Log with data changes without affecting the structure of the database and SQL queries.

Database connection

Connect your PostgreSQL source database on to start ingesting and storing all data changes stitched together with application-specific context. The database connection details can be securely configured through the dashboard UI in a few seconds.


Once your destination PostgreSQL database has been fully provisioned, you'll see a "Connected" status. You can now test the connection after making database changes in your connected source database:

psql postgres://[USERNAME]:[PASSWORD]@[HOSTNAME]:5432/[DATABASE] -c 'SELECT "primary_key", "table", "operation", "before", "after", "context", "committed_at" FROM changes;'

primary_key | table | operation | before | after | context | committed_at
26 | todo | CREATE | {} | {"id": 26, "task": "Sleep", "isCompleted": false} | {"method": "POST", "endpoint": "/todos", "payload": {"task": "Sleep", "isCompleted": false} | 2023-12-11 17:09:09+00
27 | todo | CREATE | {} | {"id": 27, "task": "Eat", "isCompleted": false} | {"method": "POST", "endpoint": "/todos", "payload": {"task": "Eat", "isCompleted": false}} | 2023-12-11 17:09:11+00
28 | todo | CREATE | {} | {"id": 28, "task": "Repeat", "isCompleted": false} | {"method": "POST", "endpoint": "/todos", "payload": {"task": "Repeat", "isCompleted": false}} | 2023-12-11 17:09:13+00
26 | todo | UPDATE | {"id": 26, "task": "Sleep", "isCompleted": false} | {"id": 26, "task": "Sleep", "isCompleted": true} | {"method": "PUT", "endpoint": "/todos/26/complete", "payload": {}} | 2023-12-11 17:09:15+00
27 | todo | DELETE | {"id": 27, "task": "Eat", "isCompleted": false} | {} | {"method": "DELETE", "endpoint": "/todos/27", "payload": {}} | 2023-12-11 17:09:18+00

See Destination Database for more details.


Distributed under the terms of the LGPL-3.0. If you need to modify and distribute the code, please release it to contribute back to the open-source community.