Skip to main content
FirstFlow is open-source under the MIT license. It is not a platform you deploy and operate it is a set of SDK packages you embed in your own product. There is no FirstFlow backend, no dashboard, and no service to keep running. Authored content lives in your git repo; runtime data lives in a Supabase project you own. This page explains what actually runs when you use FirstFlow: the three packages, where each piece of state lives, and what “self-hosting” means for a client-evaluated SDK. Read it before the Quickstart so the steps there have a model to hang on.
The whole product is these packages plus your Supabase project. “Self-hosting” here just means the data and the rendering both stay on infrastructure you control there is no separate service to run.

The model

FirstFlow has three parts, and you own all three:
  • Authored content your experiences (onboarding, tours, surveys, announcements) as experiences.json (or .ts) committed to your git repo. Changing an experience is a normal code change and deploy.
  • The runtime @firstflow/runtime, a React widget that loads those experiences, evaluates triggers and audience rules in the browser, renders the active step, and persists progress.
  • Your data a Supabase (Postgres) project you create. Flow runs, LLM calls, conversations, and traces are written to firstflow_* tables there. FirstFlow never sees your data.
There is no socket and no server-side eligibility engine. Triggers, frequency caps, audience conditions, and branching are all evaluated client-side by @firstflow/runtime from the experiences you ship. The Supabase calls persist and resume progress; they do not decide what to show.

The three packages

The frontend package is the only one you strictly need. The server package is optional add it when you want LLM observability or intent classification. config-schema ships the SQL migrations you apply to your Supabase project.

Where state lives

Nothing is hidden in a FirstFlow-operated service, because there isn’t one.
  • Experiences your git repo, imported into the app at build time.
  • Progress and resume firstflow_flow_runs in your Supabase, via the persistence adapter you pass to the provider.
  • LLM observability firstflow_llm_calls, firstflow_conversations, firstflow_conversation_messages, firstflow_traces, written by @firstflow/runtime-server.
  • End-user identity whatever your app passes as user.id. FirstFlow trusts it; your own auth decides who the user is. Unidentified visitors get a stable anonymous id.

What self-hosting requires

Three things, and the first is the only hard requirement:
  1. A Supabase project with the FirstFlow migrations applied. See Set up Supabase.
  2. A clone of the repo with your app built inside its workspace (the packages aren’t on npm you reference them with workspace:*). See Quickstart.
  3. An LLM client of your own (Anthropic, OpenAI, or any OpenAI-compatible endpoint) only if you use the intent classifier or wrap an LLM. You build the client and give it a key from any source; FirstFlow just wraps it and reads no key itself. Everything else runs without one.

What you are responsible for

Self-hosting an SDK is light on operations, because you are not running a FirstFlow server you are running your app against your Supabase. Your duties are the database (provisioning, Row Level Security, backups), keeping the Supabase service-role key server-only, and applying migrations as they ship. The full division of labor is in Responsibilities, and the hardening list is in Production.

Next

Quickstart

Install, point at Supabase, and render your first experience.

Set up Supabase

Create the project and apply the migrations.

Configuration

The environment variables FirstFlow actually reads.

Production

RLS, key hygiene, and backups before you go live.