Back to Realtime

Developing Supabase Realtime

DEVELOPERS.md

2.90.16.4 KB
Original Source

Developing Supabase Realtime

Table of contents

Client

Client libraries

LanguageSourcePackage
JavaScriptsupabase-js/realtime-js@supabase/realtime-js
Flutter/Dartsupabase-flutter/realtime_clientrealtime_client
Pythonsupabase-py/realtimerealtime
Swiftsupabase-swift/Realtimesupabase-swift

Server

Server Setup

Pre-requisites:

  • mise installed and activated so it can load env vars in your shell.

Optional but recommended:

To run the server locally, start the Postgres databases based on supabase/postgres that contains all plugins and config required by Realtime:

bash
mise run db-start

With the database running, setup deps and start the server:

bash
mix setup
mise run dev

To start another node in the local cluster (optional):

bash
mise run dev-orange

Once the server is up, open http://localhost:4000/status to check the services are running.

Note To run the whole stack in containers instead of installing Elixir locally:

bash
mise run realtime-start

Useful cleanup commands:

bash
mise run db-rm
mise run realtime-rm

To see all available tasks:

bash
mise task ls

Tenants

A tenant has already been added on your behalf. You can confirm this by checking the _realtime.tenants and _realtime.extensions tables inside the database.

Note Supabase runs Realtime in production with a separate database that keeps track of all tenants. For local development, the compose setup creates the _realtime schema for you.

You can add your own by making a POST request to the server. You must change both name and external_id while you may update other values as you see fit:

bash
  curl -X POST \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE2NzEyMzc4NzMsImV4cCI6MTcwMjc3Mzk5MywiYXVkIjoiIiwic3ViIjoiIn0._ARixa2KFUVsKBf3UGR90qKLCpGjxhKcXY4akVbmeNQ' \
  -d $'{
    "tenant" : {
      "name": "realtime-dev",
      "external_id": "realtime-dev",
      "jwt_secret": "a1d99c8b-91b6-47b2-8f3c-aa7d9a9ad20f",
      "extensions": [
        {
          "type": "postgres_cdc_rls",
          "settings": {
            "db_name": "postgres",
            "db_host": "host.docker.internal",
            "db_user": "postgres",
            "db_password": "postgres",
            "db_port": "5432",
            "region": "us-west-1",
            "poll_interval_ms": 100,
            "poll_max_record_bytes": 1048576,
            "ssl_enforced": false
          }
        }
      ]
    }
  }' \
  http://localhost:4000/api/tenants

Note The Authorization token is signed with the secret set by API_JWT_SECRET in the local compose environment.

If you want to listen to Postgres changes, you can create a table and then add the table to the supabase_realtime publication:

sql
create table test (
  id serial primary key
);

alter publication supabase_realtime add table test;

You can start playing around with Broadcast, Presence, and Postgres Changes features either with the client libs (e.g. @supabase/realtime-js), or use the built in Realtime Inspector on localhost, http://localhost:4000/inspector/new (make sure the port is correct for your development environment).

The WebSocket URL must contain the subdomain, external_id of the tenant on the _realtime.tenants table, and the token must be signed with the jwt_secret that was inserted along with the tenant.

If you're using the default tenant, the URL is ws://realtime-dev.localhost:4000/socket (make sure the port is correct for your development environment), and you can use eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDMwMjgwODcsInJvbGUiOiJwb3N0Z3JlcyJ9.tz_XJ89gd6bN8MBpCl7afvPrZiBH6RB65iA1FadPT3Y for the token. The token must have exp and role (database role) keys.

WebSocket

WebSocket URL

The WebSocket URL is in the following format for local development: ws://[external_id].localhost:4000/socket/websocket

If you're using Supabase's hosted Realtime in production the URL is wss://[project-ref].supabase.co/realtime/v1/websocket?apikey=[anon-token]&log_level=info&vsn=1.0.0"

WebSocket Connection Authorization

WebSocket connections are authorized via symmetric JWT verification. Only supports JWTs signed with the following algorithms:

  • HS256
  • HS384
  • HS512

Verify JWT claims by setting JWT_CLAIM_VALIDATORS:

e.g. {'iss': 'Issuer', 'nbf': 1610078130}

Then JWT's "iss" value must equal "Issuer" and "nbf" value must equal 1610078130.

Note:

JWT expiration is checked automatically. exp and role (database role) keys are mandatory.

Authorizing Client Connection: You can pass in the JWT by following the instructions under the Realtime client lib. For example, refer to the Usage section in the @supabase/realtime-js client library.