Skip to main content
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.
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.

Steps

1

Create a project

Create a free project at supabase.com/dashboard. Pick a region close to your app’s servers to keep persistence writes fast.
2

Apply the schema one file

Open the Supabase SQL Editor, paste 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.
schema.sql is the whole schema in one file the fast path for a new project. The numbered files in migrations/ are the same changes split incrementally, for upgrading a project you set up earlier.
3

Collect the keys

From Settings → API, copy these into your app’s environment:The anon key is what the browser runtime uses to persist flow runs (governed by RLS). 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.
4

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.

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.

Upgrading later

When you bump @firstflow/config-schema, apply any new numbered files from 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 for the full environment reference, then Row Level Security to lock down who can read and write the firstflow_* tables.