# Overview

> Feature modules for SaaS apps, each a set of SQL modules in your schema with an optional TypeScript side under better-supabase/blocks.

Source: https://bettersupabase.com/docs/blocks

A block is a feature most SaaS apps build by hand: organizations and
invitations, background jobs, notifications, outgoing webhooks, plan
entitlements. Each block installs one or more [SQL modules](/docs/blocks/sql)
into `supabase/schemas` with `better-supabase sql add`, and blocks with a
TypeScript side import it from `better-supabase/blocks/<name>`. Blocks that are
SQL only have no subpath; you call their functions from policies and RPCs.

```bash
pnpm better-supabase sql add organizations invitations
```

```ts
import { createOrganizations } from "better-supabase/blocks/organizations";
```

To build several blocks with one set of options, and wire the blocks that
use each other, use [`createBlocks`](/docs/blocks/create-blocks) from
`better-supabase/blocks`.

A block can be extended without forking it: add your own columns and type
them with a Standard Schema, steer its methods with hooks in TypeScript or
SQL, wrap its transport with middleware and add methods. See
[Extending blocks](/docs/extending/blocks).

List the modules to keep in sync in `sql.modules` in `better-supabase.config.ts`,
keyed by module name, with each module's settings as the value. The primitives that every app
uses, such as [list queries](/docs/platform/list),
[storage](/docs/platform/storage) and [realtime topics](/docs/platform/realtime),
are not blocks and keep their top-level subpaths.

## Connections [#connections]

A block's TypeScript side runs its SQL functions through a connection you
pass in. It never opens a pool of its own.

| Connection                                                              | What it runs as                             | Blocks                                                        |
| ----------------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------- |
| `ctx.postgresAdmin` from `withPostgresAdminClient` (`@supabase/server`) | The connection-string role, bypassing RLS   | jobs, idempotency, webhook inbox, outbox, audit, webhooks out |
| `ctx.postgres` from `withPostgresClient`                                | The caller, with RLS                        | organizations, notifications (through `sqlTransport`)         |
| `createPostgres()` from `better-supabase/postgres`                      | `admin`, or a user through `asUser(claims)` | every block                                                   |
| `rpcTransport(supabase)` over PostgREST                                 | The client's session, or the secret key     | organizations, notifications, webhooks out                    |

Every function that takes a SQL client accepts `@supabase/server`'s Postgres
clients as they are, so an app that already composes `withPostgresClient` and
`withPostgresAdminClient` keeps one pool and one connection string
(`SUPABASE_DB_URL` by default, or `connectionString`). `withBlock` from
`better-supabase/server` builds a block on the pipeline context; see
[middleware](/docs/auth/middleware).

`@supabase/server` runs each query in its own transaction. A block call is
one SQL function, so that changes nothing for the blocks, but
`outbox.emit()` then commits on its own instead of with the writes before it.
Emit from SQL (`emit_event` inside the function that writes) when the event
must commit with the write.

A SQL connection needs TCP: Node, Deno, Bun and the Supabase Edge runtime have
it, Cloudflare Workers and other isolates without sockets do not. There, use
`rpcTransport` for the blocks that call only SQL functions (organizations,
notifications, outgoing webhooks, flags, announcements and the rest of the
blocks that take a `transport`, and `createOutbox`, which takes a transport in
place of the SQL client), and the `pgmq_public` RPCs for jobs. The
TypeScript helpers of the idempotency keys, the webhook inbox, incoming
webhooks, route rate limits and `exportAuditLog` still need a SQL connection,
but every function a module grants, the service-role ones of `jobs`,
`idempotency`, `webhook-inbox` and `access` included, gets an entry point in
the API schema, so a server can call them over the Data API. Give
the module an API schema (`sql.modules.<module>.api`, see
[SQL modules](/docs/blocks/sql#calling-a-module-over-the-data-api)), expose
that schema, and pass it as `rpcTransport(supabase, { schema: "api" })`. Never
expose the module schema itself.

## Blocks [#blocks]

| Block                                                       | Subpath                                                                                                                            | SQL modules                            |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| [Access contract](/docs/blocks/access)                      | none                                                                                                                               | `access`, `tenant`                     |
| [Organizations and invitations](/docs/blocks/organizations) | `better-supabase/blocks/organizations`                                                                                             | `organizations`, `invitations`         |
| [Profiles](/docs/blocks/profiles)                           | `better-supabase/blocks/profiles`                                                                                                  | `profiles`                             |
| [Audit log](/docs/blocks/audit)                             | `better-supabase/blocks/audit`                                                                                                     | `audit`                                |
| [Jobs, idempotency and webhook inbox](/docs/blocks/jobs)    | `better-supabase/blocks/jobs`                                                                                                      | `jobs`, `idempotency`, `webhook-inbox` |
| [Outbox](/docs/blocks/outbox)                               | `better-supabase/blocks/outbox`                                                                                                    | `outbox`                               |
| [Durable streams](/docs/blocks/streams)                     | `better-supabase/streams`, `better-supabase/streams/redis`                                                                         | `streams`                              |
| [Workflows](/docs/blocks/workflows)                         | `better-supabase/blocks/workflows`, `better-supabase/blocks/workflows/react`                                                       | `workflows`                            |
| [Workflow SDK](/docs/blocks/workflow-sdk)                   | `better-supabase/workflow-sdk`, `better-supabase/workflow-sdk/world`                                                               | `workflow-sdk-world`                   |
| [Workflow builder](/docs/blocks/workflow-builder)           | `better-supabase/blocks/workflow-builder`, `better-supabase/blocks/workflow-builder/react`, `better-supabase/workflow-sdk/builder` | `workflow-builder`                     |
| [Notifications](/docs/blocks/notifications)                 | `better-supabase/blocks/notifications`, `better-supabase/blocks/notifications/react`                                               | `notifications`                        |
| [Inbox](/docs/blocks/inbox)                                 | `better-supabase/blocks/inbox`, `better-supabase/blocks/inbox/react`, `better-supabase/chat-sdk`                                   | `inbox`, `chat-sdk-state`              |
| [Outgoing webhooks](/docs/blocks/webhooks-out)              | `better-supabase/blocks/webhooks`                                                                                                  | `webhooks-out`                         |
| [Incoming webhooks](/docs/blocks/webhooks-in)               | `better-supabase/blocks/webhooks`                                                                                                  | `webhooks-in`, `webhook-inbox`         |
| [API keys](/docs/blocks/api-keys)                           | `better-supabase/blocks/api-keys`                                                                                                  | `api-keys`                             |
| [Settings](/docs/blocks/settings)                           | `better-supabase/blocks/settings`                                                                                                  | `settings`                             |
| [Usage and quotas](/docs/blocks/usage)                      | `better-supabase/blocks/usage`                                                                                                     | `usage`                                |
| [Billing](/docs/blocks/billing)                             | `better-supabase/blocks/billing`                                                                                                   | `billing`                              |
| [Feature flags](/docs/blocks/flags)                         | `better-supabase/blocks/flags`                                                                                                     | `flags`                                |
| [Comments and activity](/docs/blocks/comments)              | `better-supabase/blocks/comments`                                                                                                  | `comments`                             |
| [Attachments](/docs/blocks/attachments)                     | `better-supabase/blocks/attachments`                                                                                               | `attachments`                          |
| [Data lifecycle](/docs/blocks/data-lifecycle)               | `better-supabase/blocks/data-lifecycle`                                                                                            | `data-lifecycle`                       |
| [SSO and SCIM](/docs/blocks/sso)                            | `better-supabase/blocks/sso`                                                                                                       | `sso`                                  |
| [Onboarding](/docs/blocks/onboarding)                       | `better-supabase/blocks/onboarding`, `better-supabase/blocks/onboarding/react`                                                     | `onboarding`                           |
| [Waitlist and invite codes](/docs/blocks/waitlist)          | `better-supabase/blocks/waitlist`                                                                                                  | `waitlist`                             |
| [Announcements](/docs/blocks/announcements)                 | `better-supabase/blocks/announcements`, `better-supabase/blocks/announcements/react`                                               | `announcements`                        |
| [Entitlements](/docs/blocks/entitlements)                   | `better-supabase/blocks/entitlements`                                                                                              | `entitlements`                         |
| [Vector search](/docs/blocks/vector-search)                 | none (`db.$search` in the core)                                                                                                    | `vector-search`                        |
| [AI chat](/docs/blocks/ai-chat)                             | `better-supabase/blocks/ai-chat`, `better-supabase/blocks/ai-chat/react`                                                           | `ai-chat`                              |
| [AI files](/docs/blocks/ai-files)                           | `better-supabase/blocks/ai-files`                                                                                                  | `ai-files`                             |
| [Knowledge](/docs/blocks/knowledge)                         | `better-supabase/blocks/knowledge`                                                                                                 | `knowledge`                            |
| [Memory](/docs/blocks/memory)                               | `better-supabase/blocks/memory`                                                                                                    | `memory`                               |
| [Agents](/docs/blocks/agents)                               | `better-supabase/blocks/agents`                                                                                                    | `agents`                               |
| [Connectors](/docs/blocks/connectors)                       | `better-supabase/blocks/connectors`                                                                                                | `connectors`                           |
| [AI tasks](/docs/blocks/ai-tasks)                           | `better-supabase/blocks/ai-tasks`                                                                                                  | `ai-tasks`                             |
| [Push notifications](/docs/blocks/push)                     | `better-supabase/blocks/push`                                                                                                      | `push`                                 |
| [AI cache](/docs/blocks/ai-cache)                           | `better-supabase/blocks/ai-cache`                                                                                                  | `ai-cache`                             |
| [AI providers](/docs/blocks/ai-providers)                   | `better-supabase/blocks/ai-providers`                                                                                              | `ai-providers`                         |
| [Credentials](/docs/extending/credentials)                  | `better-supabase/credentials`, `better-supabase/vercel-connect`                                                                    | `credentials`                          |

## SDK adapters [#sdk-adapters]

An adapter connects a third-party SDK to the blocks above. It owns no tables
and no SQL modules of its own: install the modules of the blocks it uses.

| Adapter                                   | Subpath                                                                               | Uses the SQL modules of                                                                          |
| ----------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [AI SDK](/docs/ai-sdk)                    | `better-supabase/ai-sdk` and its `chat`, `files`, `cache`, `memory` and other entries | `ai-chat`, `ai-files`, `ai-cache`, `memory`, `knowledge`, `agents`, `connectors`, `ai-providers` |
| [Chat SDK](/docs/chat-sdk)                | `better-supabase/chat-sdk`, `better-supabase/chat-sdk/react`                          | `chat-sdk-state`, `inbox`                                                                        |
| [Workflow SDK](/docs/blocks/workflow-sdk) | `better-supabase/workflow-sdk`, `better-supabase/workflow-sdk/world`                  | `workflow-sdk-world`, `workflows`                                                                |
| [eve](/docs/eve)                          | `better-supabase/eve`                                                                 | `workflow-sdk-world`, `ai-chat`, `memory`, `knowledge`, `credentials`, `inbox`                   |

## How modules work together [#how-modules-work-together]

`sql add` installs a module with the modules it requires. The modules it
works with are optional: when one of them is installed too, the module calls
it (it queues a job, sends a notification, checks a plan), and without it the
module installs and runs without that step. Every module also writes its
events to the [outbox](/docs/blocks/outbox) when the outbox is installed.
`better-supabase sql list` prints both lists for each module.

| Module               | Requires                                | Works with                                                                 |
| -------------------- | --------------------------------------- | -------------------------------------------------------------------------- |
| `updated-at`         | none                                    | none                                                                       |
| `actor`              | none                                    | none                                                                       |
| `audit`              | none                                    | `access`, `organizations`                                                  |
| `tenant`             | `updated-at`                            | `access`, `invitations`, `organizations`                                   |
| `invitations`        | `tenant`, `access`, `updated-at`        | `organizations`, `profiles`                                                |
| `reserved-slugs`     | none                                    | none                                                                       |
| `jobs`               | none                                    | none                                                                       |
| `idempotency`        | none                                    | none                                                                       |
| `webhook-inbox`      | none                                    | none                                                                       |
| `realtime-tables`    | none                                    | none                                                                       |
| `jsonb-schemas`      | none                                    | none                                                                       |
| `pgtap`              | none                                    | none                                                                       |
| `grants`             | none                                    | none                                                                       |
| `read-sets`          | none                                    | none                                                                       |
| `mfa`                | none                                    | none                                                                       |
| `entitlements`       | `tenant`                                | none                                                                       |
| `rate-limit`         | none                                    | none                                                                       |
| `vector-search`      | none                                    | none                                                                       |
| `access`             | `tenant`                                | `invitations`, `organizations`                                             |
| `support-sessions`   | `access`, `audit`                       | `invitations`                                                              |
| `organizations`      | `tenant`, `access`, `updated-at`        | `audit`, `data-lifecycle`, `entitlements`, `invitations`, `reserved-slugs` |
| `profiles`           | none                                    | `tenant`                                                                   |
| `outbox`             | none                                    | none                                                                       |
| `notifications`      | `updated-at`                            | `access`, `profiles`                                                       |
| `webhooks-out`       | `updated-at`                            | `access`                                                                   |
| `sessions`           | none                                    | none                                                                       |
| `webhooks-in`        | `access`, `updated-at`, `webhook-inbox` | none                                                                       |
| `api-keys`           | `tenant`, `access`                      | none                                                                       |
| `settings`           | `tenant`, `access`                      | `jsonb-schemas`                                                            |
| `usage`              | `tenant`, `access`                      | `entitlements`                                                             |
| `billing`            | `tenant`, `access`                      | `organizations`                                                            |
| `flags`              | `tenant`                                | `access`, `entitlements`                                                   |
| `comments`           | `tenant`, `access`                      | `jsonb-schemas`, `notifications`                                           |
| `attachments`        | `tenant`, `access`                      | none                                                                       |
| `data-lifecycle`     | `tenant`, `access`                      | every installed module                                                     |
| `sso`                | `tenant`, `access`                      | `organizations`                                                            |
| `onboarding`         | `tenant`, `access`                      | `outbox`                                                                   |
| `waitlist`           | `tenant`, `access`                      | `invitations`, `organizations`                                             |
| `announcements`      | `tenant`, `access`                      | `entitlements`                                                             |
| `streams`            | none                                    | none                                                                       |
| `credentials`        | none                                    | none                                                                       |
| `workflows`          | `tenant`, `access`                      | none                                                                       |
| `workflow-sdk-world` | `workflows`, `jobs`, `access`           | none                                                                       |
| `workflow-builder`   | `workflows`, `tenant`, `access`         | none                                                                       |
| `chat-sdk-state`     | none                                    | none                                                                       |
| `inbox`              | `tenant`, `access`, `updated-at`        | `jobs`, `notifications`                                                    |
| `ai-chat`            | `tenant`, `access`, `streams`           | `entitlements`, `ai-providers`                                             |
| `ai-files`           | `tenant`, `access`                      | `ai-chat`                                                                  |
| `knowledge`          | `tenant`, `access`, `vector-search`     | `ai-chat`, `ai-files`, `jobs`                                              |
| `memory`             | `tenant`, `access`, `vector-search`     | `ai-chat`                                                                  |
| `agents`             | `tenant`, `access`                      | none                                                                       |
| `connectors`         | `tenant`, `access`                      | none                                                                       |
| `ai-tasks`           | `tenant`, `access`                      | `agents`, `ai-chat`, `jobs`                                                |
| `push`               | none                                    | none                                                                       |
| `ai-cache`           | none                                    | none                                                                       |
| `ai-providers`       | `tenant`, `access`                      | `ai-chat`                                                                  |
| `ensure-rls`         | none                                    | none                                                                       |

The other SQL modules (`updated-at`, `actor`, `rate-limit`,
`support-sessions` and the rest) are listed on the
[SQL modules](/docs/blocks/sql#modules) page. The
[roadmap](/docs/roadmap) lists what comes next.