Series: supabase-series · Part 10
Dev Productivity & Tools
Deploy, CI/CD and multi-project
Deploy migrations safely; CI/CD (secrets, branch); multiple projects dev/staging/prod; secure keys; deploy checklist.
2026-03-173 min read
- 0.Series: Supabase from setup to deploy
- 1.Supabase overview
- 2.Project setup, CLI and environment variables
- 3.Postgres schema and table design
- 4.Migrations: write and apply
- 5.Auth: JWT, session and backend integration
- 6.Prisma + Supabase: connect and sync schema
- 7.Row Level Security (RLS) and policies
- 8.API: PostgREST vs custom API and when to use which
- 10.Deploy, CI/CD and multi-project(this post)
Introduction
Final post in the series: deploy migrations safely, CI/CD (secrets, branch), multiple projects (dev / staging / prod) and secure keys. Apply environment separation, no logging of secrets, and a deploy checklist (manifest) when needed.
Goal: Have a consistent process for deploying migrations and app; clear dev/staging/prod split; keys and secrets never in repo or logs.
Features
Deploy migration
- Local → cloud: After testing the migration locally (
supabase db reset), link the project (staging first):supabase link --project-ref <staging-ref>, thensupabase db push. Verify the app runs correctly on staging before pushing to production. - Rollback: There is no automatic "migration rollback"; to undo, you have to write a new migration (ALTER/DROP). Back up the DB before pushing large or risky migrations.
CI/CD
- Secret: Put SUPABASE_SERVICE_ROLE_KEY, JWT secret, and DB password in CI/CD variables (GitHub Secrets, GitLab CI variables); never store them in the repo. Scripts read only from env.
- Branch: Typically
main(orproduction) deploys to prod; other branches deploy to preview/staging. Migrations should run in the deploy step (e.g.supabase link+supabase db push) with secrets coming from CI. - Deploy checklist: Document the steps: build → run migration (staging then prod) → deploy app → smoke test. Call it a "deployment checklist" or "release runbook"; it helps you avoid skipping steps (e.g. forgetting to push a migration).
Multi-project
- Model: One Supabase project per environment (dev, staging, prod) → different URLs and keys; the app in each env reads the right set of variables. Or one project with multiple branches (Supabase Branching) if you use that feature.
- Shared vs dedicated: "Dedicated" = one project per app/microservice (separate DBs); "shared" = multiple apps using the same project. Choose based on your data isolation needs and cost.
Workflow / Process
- Preparation: The repo has
supabase/migrations/; CI has SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY variables (or a DB URL for migrations) for each env. - Merge PR: After merging into the corresponding branch, the pipeline builds and tests. Deploy step: link the project (ref from env) →
supabase db push(run new migrations) → deploy the app (build, deploy serverless or container). - Env order: Deploy to staging first; verify (manual testing or E2E); then deploy to production. Migrations always run before or together with deploying a schema-compatible app.
- Audit: Don't log URLs, keys, or tokens in CI logs; use pre-commit or CI checks to ensure no file containing
service_roleor a password gets committed.
Convention: A deploy checklist (steps, order, person responsible) for each release; secrets only in env / a secret manager.
Sample code
CI (GitHub Actions) — example migration deploy step
- name: Push migrations (staging)
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
run: |
npx supabase link --project-ref ${{ secrets.SUPABASE_STAGING_REF }}
npx supabase db push
# Don't echo the real token/ref to the logDeploy checklist (markdown in the repo)
## Deploy production
1. Make sure staging runs cleanly with the new migration.
2. In CI: run the prod deploy job (link prod project, db push, deploy app).
3. Smoke test: login, create a resource, check Realtime if applicable.
4. If it fails: check logs (no secrets), roll back the app or handle the migration per the runbook.Separating env in the app
# .env.staging
SUPABASE_URL=https://xxx-staging.supabase.co
SUPABASE_ANON_KEY=...
# .env.production
SUPABASE_URL=https://xxx-prod.supabase.co
SUPABASE_ANON_KEY=...The app reads the right file based on NODE_ENV or the DEPLOY_ENV variable; don't hardcode URLs/keys.
Applying it in the architecture
- Environment separation: Dev/staging/prod each have their own project and set of variables; deploy migrations and the app in order, staging before prod. Avoid sharing a DB across environments.
- Don't log secrets: URLs can be logged (usually not sensitive); keys, passwords, and tokens must never be printed to logs or responses. CI and pre-commit check for key-leak patterns.
- Deploy checklist: Having clear steps (migration → deploy app → verify) reduces human error and makes mental rollback easier (you know how far you've gotten).
Conclusion
The 10-post series ends here: from the Supabase overview, setup, schema, migrations, auth, Prisma, RLS, API, Realtime/Edge through to deploy and CI/CD. Apply environment separation, secure secrets, and a deploy checklist for stable operations.
Back to the start of the series: 00 — Series introduction
Further reading: Supabase — Self-hosting, Branching (if used).
