# Supabase

Real data in Fayz follows the **BYOS — bring your own Supabase** model: you create the project, point the app at it, and `fayz db apply` provisions the **same schema shape** the platform uses (the [core library](/en/docs/data/model) + each plugin's versioned modules + your incubator ones). Going from `mock` mode to real data is, in the end, one command. This page is the reference for the flow; the guided walkthrough is in [tutorial 05](/en/docs/tutorial/05-real-data-with-supabase).

The path has four steps: **create the project → fill in `.env` → run `fayz db apply` → flip the provider**. `db apply` reads the installed packages, builds the migration order (core → versioned plugin modules → incubator) and applies it to **your** project via the Management API.

{% callout type="info" %}
**Architecture in transition.** These docs describe the **target shape** — the `core` library and plugin tables with the `plg_` prefix — that is shipping with the *industry pools* wave. The package wave published today still carries the previous naming (the CLI, for instance, labels the first plan step `spine`, which becomes `core`). The command and the flow are already these; only the internal labels migrate along with the wave. Where the text shows real CLI output, it appears with the current label.
{% /callout %}

## The four credentials

A Supabase project gives you four values, with different roles:

- **Project URL** and **anon key** (Project Settings → API) — these go to the browser, they're public.
- **Project ref** (Project Settings → General) — the project identifier.
- **Personal access token / PAT** (Account → Access Tokens) — a machine secret; never goes to the browser or to Git.

In `.env.local` (git-ignored) they're separated by prefix: `VITE_` for what's public, no prefix for what's tooling.

```bash
# Runtime (these go to the browser — public values only)
VITE_SUPABASE_URL=https://YOUR-REF.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key

# Tooling (used by `fayz db apply` — these do NOT go to the browser)
SUPABASE_PROJECT_REF=your-project-ref
SUPABASE_PAT=your-personal-access-token
```

The CLI also accepts the aliases `SUPABASE_REF` and `SUPABASE_ACCESS_TOKEN`, and reads first from the process environment, then from `<app>/.env.local`, then from `<app>/.env` (the files never override the environment).

## Plan before you apply (dry-run)

`--dry-run` makes no network calls and doesn't read your PAT — it's always safe to run:

```bash
npx @fayz-ai/cli db apply --dry-run
```

{% callout type="tip" %}
`--dry-run` assumes you've already run `npm install`: it reads the `@fayz-ai/*` packages from your `node_modules` to build the plan. Without `@fayz-ai/db` installed, the command **errors** instead of printing the plan — install your dependencies first.
{% /callout %}

It prints the ordered plan and stops. The order is **always** the same: **core** first, then each **plugin's versioned migrations**, and finally your **incubator** ones. In the current CLI output this shows up with the labels:

```
spine → drizzle → seed → plugins → incubator
```

where `spine`/`drizzle`/`seed` are the core steps (the label moves to `core` in the *industry pools* wave), `plugins` are each plugin's versioned modules, and `incubator` are your tables. A step only shows up if the corresponding package ships SQL files. With the current package versions the plan is still lean — as plugins start shipping migrations, new steps appear here. Don't be surprised by an "empty core" warning in the dry-run: the published `@fayz-ai/db` doesn't ship migrations in this generation yet, and the command itself tells you which version fixes that.

## Apply for real

Once the plan looks the way you want, apply it. This command runs with **your** credentials and writes to the database:

```bash
npx @fayz-ai/cli db apply
```

It asks for confirmation before applying; use `--yes` to skip the prompt in CI. Without `SUPABASE_PROJECT_REF` and `SUPABASE_PAT` set, it stops with a clear error — on purpose, so it never applies against the wrong project. Useful flags for applying in pieces:

| Flag | Effect |
| --- | --- |
| `--dry-run` | Only prints the ordered plan; no network calls. |
| `--yes`, `-y` | Skips the confirmation (required in non-interactive shells). |
| `--spine-only` | Applies only the core from `@fayz-ai/db` (the flag keeps the `spine` label in the current wave). |
| `--plugins-only` | Applies only the plugin + incubator migrations. |
| `--only-plugins a,b` | Restricts the plugins step to the named ids. |

## Flip the switch

With the schema in place, switch the backend in `app.manifest.json` from `mock` to `supabase` and set the ref:

```json
{
  "backend": {
    "provider": "supabase",
    "projectRef": "your-project-ref"
  }
}
```

And validate:

```bash
npx @fayz-ai/cli doctor
```

`fayz db apply` handles the layer ordering for you — core, then the plugin modules, then your incubator ones — in your own Supabase. You never write the core SQL by hand. To understand what's being created, see [Data model](/en/docs/data/model).

---

Next: how isolation between tenants is guaranteed in [RLS and multi-tenancy](/en/docs/data/rls).
