supabase-rb-rb
Initializing

Initializing

Install supabase-rb and construct a Supabase::Client.

supabase-rb is a single gem that bundles Auth, PostgREST (Database), Storage, Edge Functions, and Realtime behind one umbrella client. Supabase.create_client is the entry point — pass your project URL and an API key, get back a Supabase::Client.

Install

Add the gem to your Gemfile:

# Gemfile
gem "supabase-rb"

Then run:

bundle install

Or install it directly without bundler:

gem install supabase-rb

Requires Ruby ≥ 3.1.

First query

A complete end-to-end example — install the gem, construct a client with your project URL + anon key, and read a row:

require "supabase"

supabase = Supabase.create_client(
  supabase_url: ENV.fetch("SUPABASE_URL"),
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY")
)

response = supabase.from("countries").select("*").limit(1).execute
puts response.data
# => [{"id" => 1, "name" => "United Kingdom"}]

SUPABASE_URL is your project URL (e.g. https://abcd1234.supabase.co) and SUPABASE_ANON_KEY is the anon (anon) key from the project's API settings.

Construct a client

Supabase.create_client(supabase_url:, supabase_key:, options: {}, async: false)

Equivalent to Supabase::Client.new(...) but routes through Client.create, which additionally restores a persisted session (if options.persist_session is enabled and the auth storage holds one) and applies the session's access token as the bearer.

NameTypeRequiredDescription
supabase_urlStringRequiredYour project URL, e.g. https://abcd1234.supabase.co.
supabase_keyStringRequiredA project API key — anon for client-side use, service-role for trusted server-side use.
optionsSupabase::ClientOptions | HashOptionalConfiguration. Accepts a ClientOptions instance, a flat hash of ClientOptions fields, or the legacy nested-hash form.
asyncBooleanOptionalWhen true, swaps every HTTP sub-client to the async-http-faraday variant. Defaults to false.
Returns
Supabase::Client

An umbrella client exposing auth, postgrest (via from/table/rpc/schema), storage, functions, and realtime (via channel).

supabase = Supabase.create_client(
  supabase_url: "https://abcd1234.supabase.co",
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY")
)

You can also call Supabase::Client.new(...) directly if you want to skip the persisted-session restore:

supabase = Supabase::Client.new(
  supabase_url: "https://abcd1234.supabase.co",
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY")
)

ClientOptions

Supabase::ClientOptions is the typed configuration struct passed via options:. A single class covers both sync and async modes because the sync/async split is decided at runtime via the umbrella async: flag (see Async mode).

Supabase::ClientOptions.new(schema: "public",headers: nil,auto_refresh_token: true,persist_session: true,realtime: nil,postgrest_client_timeout: 120,storage_client_timeout: 20,function_client_timeout: 5,flow_type: "pkce",storage: nil,http_client: nil)
NameTypeRequiredDescription
schemaStringOptionalDefault Postgres schema for PostgREST requests. Defaults to "public". Use client.schema("other") to query another schema without mutating this default.
headersHash<String, String>OptionalGlobal headers merged into every HTTP sub-client (auth, postgrest, storage, functions). Useful for X-Tenant, X-Request-Id, or overriding Authorization.
auto_refresh_tokenBooleanOptionalWhen true (default), the auth client schedules a background timer to refresh the access token before it expires.
persist_sessionBooleanOptionalWhen true (default), the auth client writes the session to the configured storage backend so it survives process restarts.
realtimeHashOptionalKeyword overrides forwarded verbatim to Realtime::Client (e.g. { transport: ..., logger: ..., timeout: 10 }).
postgrest_client_timeoutInteger (seconds)OptionalRequest timeout for PostgREST calls. Defaults to 120.
storage_client_timeoutInteger (seconds)OptionalRequest timeout for Storage calls. Defaults to 20.
function_client_timeoutInteger (seconds)OptionalRequest timeout for Edge Functions calls. Defaults to 5.
flow_typeStringOptionalOAuth flow type for the auth client. Defaults to "pkce".
storageObjectOptionalSession storage backend. Any object responding to get_item / set_item / remove_item. Defaults to in-memory storage.
http_clientFaraday::ConnectionOptionalOptional pre-built Faraday connection shared by all sub-clients. Lets you wire your own middleware, adapter, or instrumentation.
options = Supabase::ClientOptions.new(
  schema: "public",
  headers: { "X-Tenant" => "acme" },
  auto_refresh_token: true,
  persist_session: true,
  postgrest_client_timeout: 30,
  storage_client_timeout: 20,
  function_client_timeout: 10,
  flow_type: "pkce"
)

supabase = Supabase.create_client(
  supabase_url: ENV.fetch("SUPABASE_URL"),
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY"),
  options: options
)

A flat hash of the same keys works equivalently — it is canonicalized into a ClientOptions instance internally:

supabase = Supabase.create_client(
  supabase_url: ENV.fetch("SUPABASE_URL"),
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY"),
  options: { schema: "public", headers: { "X-Tenant" => "acme" } }
)

Global headers

Headers passed via options.headers are merged into every HTTP sub-client. The default X-Client-Info: supabase-rb/<version> header is always included so your project logs can attribute requests to the Ruby gem.

options = Supabase::ClientOptions.new(
  headers: { "X-Tenant" => "acme", "X-Request-Id" => SecureRandom.uuid }
)

Database schema

schema: sets the default Postgres schema for all PostgREST requests. To query a non-default schema for a single chain without changing this default, use client.schema("other"):

supabase.schema("private").from("audit_log").select("*").execute

Async mode

Pass async: true to swap every HTTP sub-client (auth, postgrest, storage, functions) to its async-http-faraday variant. Calls return values that integrate with the async gem's reactor.

require "async"
require "supabase"

Async do
  supabase = Supabase.create_client(
    supabase_url: ENV.fetch("SUPABASE_URL"),
    supabase_key: ENV.fetch("SUPABASE_ANON_KEY"),
    async: true
  )

  response = supabase.from("countries").select("*").execute
  puts response.data
end

One client, runtime async flag

Async mode is opt-in at construction time via async: true — there is no separate AsyncClient class. Request builders are transport-agnostic, so the same call sites work in both modes.

Two things to know:

  • Under async: true, client.remove_channel / client.remove_all_channels (and the set_auth fan-out to a connected realtime socket) return an Async::Task instead of blocking the calling fiber — call .wait on it to await the result.
  • The realtime client itself stays thread-based regardless of async: — only the HTTP sub-clients switch transport. The umbrella's dispatch_realtime helper bridges the two worlds for you.

Legacy nested-hash options

The original Ruby options shape — a nested hash keyed by sub-client name — is still accepted alongside ClientOptions. Existing callers don't need to migrate:

supabase = Supabase.create_client(
  supabase_url: ENV.fetch("SUPABASE_URL"),
  supabase_key: ENV.fetch("SUPABASE_ANON_KEY"),
  options: {
    auth:      { auto_refresh_token: true, persist_session: true, flow_type: "pkce" },
    postgrest: { schema: "public", timeout: 30 },
    storage:   { timeout: 20 },
    functions: { timeout: 10 },
    realtime:  { logger: Logger.new($stdout) },
    global:    { headers: { "X-Tenant" => "acme" } }
  }
)

The shape is detected automatically — presence of any of :auth, :postgrest, :functions, :global, or a Hash-valued :storage switches the client into legacy-routing mode.

Prefer ClientOptions for new code

The legacy nested-hash form is preserved for backwards compatibility with supabase-rb ≤ 3.x, when there was no equivalent of ClientOptions. New code should prefer ClientOptions (or a flat hash of its fields) — the legacy shape silently drops any ClientOptions-style keys mixed in, and the client emits a warning when it detects such stray keys.

On this page