# 05 · Real data with Supabase

So far the app has run in `mock` mode, with in-memory sample data. Now you follow the **BYOS — bring your own Supabase** model: you connect a Supabase project of your own, provision the same schema shape the platform uses (the `core` library + the plugin modules + your incubator plugins) with `fayz db apply`, and flip the switch to real, persistent data.

{% steps %}
{% step title="Create your Supabase project (BYOS)" %}
In the [Supabase dashboard](https://supabase.com/dashboard), create a new project (the free plan is enough). It's **your** database — `fayz db apply` only writes the target shape into it. You'll need four values from it:

- **Project URL** and **anon key** — under Project Settings → API. These live in the browser (public).
- **Project ref** — under Project Settings → General. It's the project identifier.
- **Personal access token (PAT)** — under Account → Access Tokens. This is a machine secret; it never goes to the browser or into Git.
{% /step %}

{% step title="Fill in .env.local" %}
The scaffold ships a `.env.example`. Copy it to `.env.local` (already in `.gitignore`) and fill it in:

```bash
cp .env.example .env.local
```

```bash
# Runtime (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` — do NOT go to the browser)
SUPABASE_PROJECT_REF=your-project-ref
SUPABASE_PAT=your-personal-access-token
```
{% /step %}

{% step title="Plan the migration (dry run)" %}
Before touching the database, look at the plan. `--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
```

Real output on a freshly created app:

```
▸ Migration plan for my-store

   1. [spine    ] @fayz-ai/db  — no files

  Notes:
    ⚠ installed @fayz-ai/db ships no migrations/ — the spine step is empty (upgrade to @fayz-ai/db >= 0.1.3 once published)
    ⚠ plugin 'dashboard': @fayz-ai/plugin-dashboard ships no src/migrations — skipped

  Summary: 1 step(s), 0 sql file(s). (dry-run — nothing was applied)
```

The plan's order is always the same: the **core** first, then each plugin's **versioned migrations**, and finally your **incubator** plugins. In the current CLI output this shows up with the labels `spine → drizzle → seed → plugins → incubator` (the first three are the core — the label moves to `core` in the *industry pools* wave). A step only appears if the corresponding package ships SQL files. With the current package versions the plan is still lean; as plugins start shipping migrations, new steps will show up here.
{% /step %}

{% step title="Apply for real" %}
Once the plan looks the way you want, apply it. This is the command that runs with **your** credentials (the `SUPABASE_PROJECT_REF` and `SUPABASE_PAT` from `.env.local`) and writes to the database via the Supabase Management API:

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

It asks for confirmation before applying (use `--yes` to skip the prompt in CI). Without both variables set, it stops with a clear error — deliberately, so it never applies against the wrong project.
{% /step %}

{% step title="Flip the switch to Supabase" %}
With the schema in place, change the backend in `app.manifest.json` from `mock` to `supabase` and give it the ref:

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

Then validate everything with doctor:

```bash
npx @fayz-ai/cli doctor
```
{% /step %}
{% /steps %}

{% callout type="tip" %}
✓ You should see: on the dry run, the line `Summary: N step(s) ... (dry-run — nothing was applied)`. After the real `db apply`, confirmation that the migration was applied. And `doctor` reporting `0 error(s)` once you've flipped `provider` to `supabase`.
{% /callout %}

The data model has three layers — the `core` library (the shared base tables), the `plg_` tables each plugin installs, and your app's own tables — all isolated by `tenant_id` with RLS. You don't need to master this now; `fayz db apply` assembles the correct order in your own Supabase. For the full map, see [Data model](/en/docs/data/model) and [RLS and multi-tenancy](/en/docs/data/rls).

---

[← Previous: 04 · Add a plugin](/en/docs/tutorial/04-add-a-plugin) · [Next: 06 · Your own plugin →](/en/docs/tutorial/06-your-own-plugin)
