> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstflow.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up Supabase

> Create the Supabase project FirstFlow writes to, apply the migrations in order, and collect the keys your app needs.

FirstFlow stores all runtime data flow runs, LLM calls, conversations, and traces in a Supabase (Postgres) project you own. This page creates that project, applies the FirstFlow schema, and collects the two keys your app uses. It is the one hard prerequisite for self-hosting.

<Note>
  Any Postgres works in principle, but the shipped persistence adapters and
  migrations target Supabase. A self-hosted Supabase behaves identically to
  Supabase Cloud only the project URL differs.
</Note>

## Steps

<Steps>
  <Step title="Create a project">
    Create a free project at [supabase.com/dashboard](https://supabase.com/dashboard).
    Pick a region close to your app's servers to keep persistence writes fast.
  </Step>

  <Step title="Apply the schema one file">
    Open the Supabase **SQL Editor**, paste
    [`packages/config-schema/supabase/schema.sql`](https://github.com/firstflowdev/firstflow-oss/blob/main/packages/config-schema/supabase/schema.sql),
    and run it once. That single script creates every table, index, trigger, and
    the default policies `firstflow_experiences`, `firstflow_flow_runs`,
    `firstflow_llm_calls`, `firstflow_traces`, `firstflow_conversations`, and
    `firstflow_conversation_messages`.

    It is idempotent (`if not exists` throughout), so re-running it is safe.

    <Tip>
      `schema.sql` is the whole schema in one file the fast path for a new
      project. The numbered files in
      [`migrations/`](https://github.com/firstflowdev/firstflow-oss/tree/main/packages/config-schema/supabase/migrations)
      are the same changes split incrementally, for upgrading a project you set
      up earlier.
    </Tip>
  </Step>

  <Step title="Collect the keys">
    From **Settings → API**, copy these into your app's environment:

    | Env var                         | Where                                | Exposure        |
    | ------------------------------- | ------------------------------------ | --------------- |
    | `NEXT_PUBLIC_SUPABASE_URL`      | Settings → API → **Project URL**     | Browser-safe    |
    | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Settings → API → `anon` `public` key | Browser-safe    |
    | `SUPABASE_SERVICE_ROLE_KEY`     | Settings → API → `service_role` key  | **Server-only** |

    The `anon` key is what the browser runtime uses to persist flow runs (governed
    by [RLS](/self-hosting/oauth-providers)). The `service_role` key bypasses RLS
    and is used **only** by `@firstflow/runtime-server` on your backend. Treat it
    like a database superuser password never ship it to the browser, never
    commit it. See [Configuration](/self-hosting/configuration).
  </Step>

  <Step title="Verify the schema">
    In **Table Editor** you should see the `firstflow_*` tables. A quick smoke
    test: run an experience in your app and confirm a row appears in
    `firstflow_flow_runs`; wrap one LLM call and confirm a row in
    `firstflow_llm_calls`.
  </Step>
</Steps>

## Strict RLS (optional)

By default the policies are **permissive** the browser writes flow runs with
the `anon` key and your app is the trust boundary. If you use Supabase Auth and
want flow-run writes locked to the signed-in user, uncomment the **STRICT RLS**
block at the bottom of `schema.sql` (it scopes writes to `auth.uid()`). See
[Row Level Security](/self-hosting/oauth-providers).

## Upgrading later

When you bump `@firstflow/config-schema`, apply any new numbered files from
[`migrations/`](https://github.com/firstflowdev/firstflow-oss/tree/main/packages/config-schema/supabase/migrations)
that you haven't run yet, in order. There is no automatic runner applying SQL
to your own database stays under your control. Re-running `schema.sql` is also
safe and brings a project up to the latest shape.

## Next

Continue to [Configuration](/self-hosting/configuration) for the full environment
reference, then [Row Level Security](/self-hosting/oauth-providers) to lock down
who can read and write the `firstflow_*` tables.
