Functions and production

Separate environments and secrets

Keep local, preview, staging, and production resources distinct, link the CLI explicitly, and prevent destructive commands from targeting the wrong project.

The Supabase CLI will happily run a destructive command against the wrong project. It has no idea which one holds your real users. Environment separation is what makes that mistake hard instead of easy.

Use separate projects, or the platform’s branching feature, for environments that must not share users or data. Local development runs on the CLI stack. Staging and production are distinct hosted projects, each with its own project reference, the twenty-character ID in its URL. Record each reference and its purpose somewhere visible, without credentials next to it:

abcdefghijkl  production  (real users, never experiment here)
mnopqrstuvwx  staging     (disposable data, safe to break)

The CLI acts on whatever project the current directory is linked to. Link it, then check the marker:

supabase link --project-ref mnopqrstuvwx
supabase projects list
#   LINKED │ REFERENCE ID  │ NAME
#  ────────┼───────────────┼────────────
#          │ abcdefghijkl  │ production
#     ●    │ mnopqrstuvwx  │ staging

The dot marks the linked project. Look at it before anything irreversible. I do this even when I’m sure, because “sure” is how the wrong project gets reset.

Say where a command runs

CLI defaults differ between commands. Some act on the local stack, some on the linked project. For destructive or production-sensitive work, don’t rely on the default. Pass the target explicitly:

supabase db reset --local            # rebuilds the local stack, always safe
supabase db push --linked --dry-run  # preview what would hit the linked project

The nightmare command is supabase db reset --linked. It rebuilds the linked project’s database from your local migration files. On production that is total data loss, and the confirmation prompt is the only thing between you and it. Review the linked project before pushing migrations, every time.

Secrets follow the same split

Each environment gets its own secret values, set where that environment runs:

supabase secrets set RESEND_API_KEY=re_8fKm2Vw... --project-ref mnopqrstuvwx
supabase secrets list --project-ref mnopqrstuvwx
#   NAME            │ DIGEST
#   RESEND_API_KEY  │ 3f9a...

The list command shows a digest, never the value, so you can confirm a secret exists without printing it.

Never reuse production credentials in staging. The whole point of the split is that a staging mistake cannot touch production data. A shared API key quietly reconnects the two: a staging test that sends email through the production key sends real email to real people.

Before your first production deploy, write a five-line release checklist in a markdown file: the source environment, the target project, the migration preview output, the smoke test to run after deploy, and who owns the rollback. Five lines in a file beat memory under pressure, every time.

Lesson completed