A Git‑driven Cursor Supabase workflow for reviewed schema, RLS and type migrations
A practical Cursor + Supabase workflow for AI‑assisted schema changes, RLS and types that never let an agent touch production directly.
What you will set up with Cursor and Supabase
The safest way to use Cursor with Supabase is to ban AI from touching production directly. Instead, you give Cursor a dedicated dev Supabase project via MCP, let it write SQL migration files and RLS policies into your repo, and promote those changes through Git, PR review and CI into staging and production. Types are regenerated in the same pipeline so your TypeScript client always matches the database.
This guide walks through a concrete implementation:
- Dev / staging / prod layout mapped to Supabase projects and billing
- How to configure Supabase MCP in Cursor with least privilege
- A repeatable migration + RLS pattern that Cursor can follow
- Type generation and CI checks wired to every schema change
The outcome: teams can still move fast with AI assistance, but the only way a schema or policy reaches production is as a reviewed migration. If you are still deciding whether Supabase is the right backend in the first place, the Supabase review for AI builders gives broader context on when this stack makes sense. If you are comparing multiple AI coding stacks, the best AI coding stack guide walks through where Cursor + Supabase fits alongside other options.
Why Cursor + Supabase needs a database-safe workflow
Cursor is positioned as an AI-first IDE with agents that can plan, write and refactor code across a repository according to its product page. Supabase runs each project as a dedicated VM and Postgres database, with compute billed per-project based on the configured compute instance size, as its billing guide explains. Combining these two without guardrails creates obvious failure modes:
- Agents running ad hoc
ALTER TABLE in production
- New tables shipped without Row Level Security (RLS)
- Mismatched types after manual SQL changes
- Cost creep from unplanned extra Supabase projects
Supabase’s RLS docs emphasise that Row Level Security is enforced at the PostgreSQL layer, and the GraphQL and Data API docs state that pg_graphql and the Data API fully respect PostgreSQL roles and row-level security policies for client-facing access. Missing policies are not just an implementation detail; they are a security boundary failure.
The workflow below treats Cursor as a planner and migration author, not a DBA with production credentials. Every structural change flows through Git, CI and explicit promotion to the next Supabase project. For teams trying to generalise this pattern to other tools, the AI coding agent PR workflow guide expands on these guardrails beyond databases, and the Cursor rules for real projects article shows how to encode these constraints directly into your repositories.
Architecture: environments, billing and the promotion path
The core pattern is simple:
Supabase’s public pricing page shows the Free plan’s limit of two active projects and the Micro compute cost of US$10 per month, grounding the environment layout and cost examples in real billing UI.
- Dev: where Cursor connects via Supabase MCP, experiments and generates migrations.
- Staging: optional but recommended; CI applies migrations here after PRs merge.
- Production: only CI (or a tightly scoped operator script) runs migrations here.
Supabase’s billing docs describe four plan families – Free, Pro, Team and Enterprise – and explain that the Free plan entitles you to two active free projects across all organizations where you are an Owner or Admin; the pricing page surfaces this as a “Limit of 2 active projects” for Free in its plan comparison. Each project is a dedicated Postgres instance, and paid organization plans include a US$10/month compute credit that can cover one Micro compute instance or offset the cost of a larger instance.
Environment layout vs Supabase cost
The table below normalises the cost trade-offs for Micro instances using Supabase’s published numbers and billing rules.
| Scenario |
Plan |
Projects |
Base subscription |
Compute (Micro) |
Credits |
Net monthly infra |
| Solo: dev + prod |
Free |
2 active |
US$0 |
US$10 × 2 = US$20 |
US$0 |
US$20 |
| Solo: one-at-a-time (pause dev) |
Free |
1 active at a time |
US$0 |
US$10 |
US$0 |
US$10 |
| Small team: dev + staging + prod |
Pro |
3 active |
US$25 |
US$10 × 3 = US$30 |
-US$10/month credit |
US$45 |
Arithmetic and assumptions:
- Supabase’s pricing page lists the Micro compute size at a nominal US$10/month per project (billed hourly over the month) in its compute calculator.
- Free has no subscription and no credit, but compute is still billed for each active project.
- Supabase’s Pro plan currently starts from US$25/month, and paid plans include US$10/month in compute credits per billing cycle.
- The billing FAQ confirms credits are applied to invoices before charging the payment method.
For the solo Free-plan builder, the safe workflow often leads to 2 projects (dev + prod). Supabase’s billing docs state that paused projects do not count towards the free project limit because they are not active, so it is possible to rotate which projects are active without exceeding the Free plan’s 2-project quota; pausing a project also stops its compute charges while it is paused.
Promotion path for schema and RLS changes
On top of that layout, the workflow enforces a strict promotion path:
- No direct SQL in production from the Supabase dashboard except in emergencies.
- All
CREATE TABLE, ALTER TABLE and CREATE POLICY statements live in versioned migrations under supabase/migrations (or your equivalent).
- Dev is the only project where experimental SQL is allowed, and even there Cursor should be nudged to emit migrations rather than ad hoc changes.
- Staging receives migrations automatically from CI after PRs merge.
- Production only receives the exact same migrations, applied in order.
Configuring Supabase MCP in Cursor (dev only)
Supabase documents a Model Context Protocol (MCP) server feature that lets AI tools such as Cursor and Claude connect to Supabase to launch databases, manage tables, and query data, as described in its MCP feature page and MCP docs in the MCP server announcement. Official documentation explains how to enable MCP server access for self-hosted Supabase instances in the enabling MCP guide, and separate MCP server docs describe how AI clients connect to hosted Supabase projects. The community supabase-mcp repository shows how Cursor and other assistants can be wired into this endpoint using MCP.
The Supabase MCP server blog post confirms MCP as an officially supported integration for connecting AI tools such as Cursor to Supabase, validating its use for safe, scoped schema introspection.
Cursor’s MCP documentation shows how to configure external MCP servers, anchoring the instructions for wiring Supabase MCP and reinforcing that this setup fits into Cursor’s standard Git-based workflow.
Step 1: create a dedicated dev project
In Supabase:
- Create a project called
myapp-dev on a Micro instance.
- Record its project URL and anon key from the API settings.
- For MCP, prepare a key with only the privileges you need. Avoid giving Cursor a service role key to production.
Step 2: enable MCP and register it in Cursor
Following Supabase’s MCP docs:
- Enable MCP access for your organisation or self-hosted instance as described in the Enabling MCP Server Access guide.
- Point Cursor at the Supabase MCP server endpoint. The Cursor community forum discusses workspace-specific MCP server configuration, which is useful if you want different connections per repo.
- Store the dev project’s keys as environment variables in Cursor for that workspace only (for example
SUPABASE_DEV_URL and SUPABASE_DEV_KEY).
The rule is simple: only dev credentials live in Cursor. Staging and production keys stay in CI/CD and runtime environments.
Step 3: set Cursor workspace rules
Cursor’s documentation explains how it integrates with GitHub and other providers, and how you can configure project-specific settings for each workspace. Use this to encode database guardrails:
- In your repo, add a
docs/AI_RULES.md describing that all schema and RLS changes must be written as SQL files under supabase/migrations.
- Tell Cursor (via the workspace instructions) to avoid executing SQL directly against production URLs or keys and to always propose migrations instead.
- Restrict agents from editing CI/CD and infrastructure files that inject production Supabase credentials.
These rules align with PR-focused discipline for AI coding agents and with repo-level rules for Cursor agents. For a deeper playbook on those instructions, see the dedicated Cursor rules for real projects article, which includes concrete examples of prompts and guardrails.
Designing a safe local schema loop with Cursor
With MCP wired to dev, teams can start using Cursor to propose schema changes. The key is to treat what Cursor does against dev as a draft that must be turned into a migration, not the source of truth.
Supabase’s RLS documentation provides canonical ALTER TABLE ENABLE ROW LEVEL SECURITY and CREATE POLICY examples, mirroring the SQL patterns this workflow has Cursor generate for every new table and exposed operation.
Step 4: explore and design against dev via MCP
Using Cursor’s chat window:
- Ask Cursor (via MCP) to list existing tables and constraints in
myapp-dev.
- Describe the feature being added and have Cursor propose a schema: tables, columns, indexes.
- Ask specifically: “Return the final design as a single SQL migration file with
CREATE TABLE, ALTER TABLE, indexes and RLS policies included.”
Supabase’s RLS docs give canonical examples of enabling RLS and policies:
ALTER TABLE public.tasks ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view their own tasks"
ON public.tasks
FOR SELECT
USING ( auth.uid() = user_id );
Cursor can be instructed to always include these patterns for any table exposed to untrusted clients.
Step 5: apply draft SQL only on dev, then freeze as a migration
A safe pattern for each feature:
- Have Cursor generate the SQL and apply it via MCP only to
myapp-dev.
- Verify behaviour in the app: tables exist, RLS behaves as expected for different users.
- Once the behaviour is validated, paste the final SQL into a new migration file in the repo, even if it is identical to what ran on dev.
Avoid copying ad hoc changes from the Supabase dashboard into production manually. Instead, maintain the rule: “If it is not in a migration file on main, it does not exist.”
Step 6: standard migration file structure
Pick a deterministic naming scheme, such as:
supabase/migrations/
20240915120000_add_tasks_table.sql
20240915121500_add_task_labels.sql
A migration should include in order:
- Idempotence checks where reasonable (for example “create table if not exists” in some cases).
- Raw DDL for tables and indexes.
ALTER TABLE... ENABLE ROW LEVEL SECURITY;
CREATE POLICY statements for SELECT, INSERT, UPDATE and DELETE as needed.
- Optional comments describing intent.
Supabase’s RLS docs show distinct policies for each operation (select, insert, update, delete), and, together with the GraphQL security docs, they explain that PostgreSQL’s row-level security policies are enforced for the GraphQL API and other Data API access paths so missing policies can expose data on those APIs. Cursor can be prompted to generate this full block for every new table.
Step 7: RLS-first prompts for Cursor
Cursor behaves much better when given explicit constraints. For each new feature, favour prompts like:
- “Design the schema and RLS policies for a
tasks table where each row belongs to a single user, identified by auth.uid(). Generate a single SQL migration that creates the table, enables RLS and adds policies for select, insert, update, delete so that users can only access their own tasks.”
- “If any table will be queried from the browser or mobile clients, treat it as untrusted access and always enable RLS with appropriate
auth.uid()-based policies.”
Cursor’s agent is then nudged away from patterns like “just create the table, we’ll add RLS later” which Supabase’s docs strongly discourage.
Wiring types into the same loop
Row-level security and schema correctness are only half of the story; type safety from Postgres through to TypeScript is also important.
Step 8: choose a type generation strategy
There are several ways to derive types. Two common patterns for Supabase-backed TypeScript apps:
- Supabase client types: generate types directly from the database schema and attach them to a Supabase JS client.
- ORM-based (for example Drizzle): define the schema in code, generate migrations from that, and derive types from the ORM definitions.
A published article on Suparbase.com describes a 2026 stack combining Cursor, Supabase, Drizzle and MCP servers for CRUD apps, illustrating that both migration-first and ORM-first patterns are viable when coordinated properly for an AI-assisted workflow.
The workflow here assumes database-first SQL migrations as the source of truth, then deriving types downstream.
Step 9: add a type generation script
In the repo’s package.json (or equivalent), add a script like:
"scripts": {
"db:types": "supabase gen types typescript --project-id $SUPABASE_DEV_PROJECT_ID --schema public > src/lib/supabase.types.ts"
}
Adjust for the schema and tooling in use. The key properties:
- It runs only against dev or staging (never directly against prod from developer machines).
- The generated file is committed to Git, so code review can see type changes alongside migrations.
- Cursor is instructed to run
npm run db:types after adding or editing migrations.
Step 10: enforce type regeneration in PRs
In CI:
- Run tests against the latest schema (applied to a temporary database or dedicated CI Supabase project).
- Run
npm run db:types and ensure there is no diff relative to the committed types.
If types have changed but were not regenerated locally, CI should fail. That prevents silent drift between TypeScript code and the Postgres schema.
CI/CD: from migrations in Git to Supabase projects
Once migrations and types are in the repository, the final piece is the automated path from Git to Supabase.
Step 11: align branches with environments
A simple mapping:
feature/*: developer branches; Cursor can freely edit migrations here.
main (or develop): maps to staging.
release or tagged commits: map to production.
CI jobs then apply migrations depending on which branch triggered the pipeline.
Step 12: migration job structure
For each relevant branch:
- Check out code and install dependencies.
- Apply migrations to the target Supabase project using the Supabase CLI or a preferred migration runner, using environment-specific URLs and keys.
- Run tests against that environment.
- Generate types (optional in CI if types are only built from dev locally, but recommended for a staging CI environment).
Crucially, only CI has access to SUPABASE_STAGING_* and SUPABASE_PROD_* secrets. Cursor never sees them.
Step 13: handling failed migrations
When an AI-generated migration fails in CI or staging, there are a few standard responses:
- If the migration has not run on production, fix the SQL in a new commit on the same PR; treat the previous failed migration as a draft.
- If the migration already ran on production and introduced a problem, create a new forward migration to adjust the schema (for example, add a missing column or change default values). Avoid editing historical migrations that have already been applied to any environment.
- Consider enabling Supabase’s Point in Time Recovery add-on for production. Supabase’s pricing page describes this as an add-on that starts from US$100 per project per month; for higher-risk workloads it acts as an additional safety net.
CI should block promotion whenever migrations fail on staging, so no broken DDL hits production automatically.
RLS best practices with AI coding tools
Given RLS is the primary boundary between tenants, it deserves explicit treatment in any AI workflow.
Step 14: default posture – RLS on for all exposed tables
Supabase’s RLS documentation recommends enabling RLS and defining policies for all tables exposed to untrusted clients. Encode that as a non-negotiable rule in repository docs and Cursor instructions:
- Any table accessed from the browser, mobile or public APIs must have RLS enabled via
ALTER TABLE... ENABLE ROW LEVEL SECURITY;.
- At minimum, add a policy for
SELECT, and often for INSERT, UPDATE and DELETE that tie user_id to auth.uid().
- Privileged operations (for example, admin dashboards) should run with a service role key from a trusted backend, not from the browser, and must still respect carefully designed policies unless absolutely internal.
Step 15: policy review as part of PRs
When reviewing a migration PR, add a checklist:
- Does every table that is client-facing have RLS enabled?
- Are the policies for each operation explicit and least-privilege?
- Do policies use
auth.uid() consistently for per-user rows, or appropriate checks for multi-tenant data?
This effectively adds RLS to code review discipline in the same way APIs or UI changes are reviewed.
Step 16: test RLS behaviour on dev and staging
Because RLS is enforced at the database level and applies to GraphQL and the Data API as Supabase’s security docs highlight, testing can be done via:
- Manual tests using different auth contexts (for example multiple test users) on dev and staging.
- Automated integration tests that use Supabase’s JS client with different JWTs to confirm that only allowed rows are visible or writable.
Cursor can help generate these tests once the pattern is demonstrated.
Safe handling of Supabase secrets in a Cursor stack
Given Cursor’s power, key discipline is essential.
Step 17: least-privilege keys per context
- Dev: MCP uses anon or a constrained service key, only for the dev project.
- Staging: keys live in CI and staging runtime only; not in developer machines or Cursor.
- Production: keys live exclusively in production infrastructure and CI; never stored in the repo, local env files shared with Cursor, or in AI prompts.
Supabase’s billing FAQ confirms each project is a separate VM and database, which reinforces the importance of mapping secrets to the right project and avoiding cross-environment key reuse.
Step 18: avoid service role keys in AI prompts
Service role keys bypass RLS, so they should be treated as highly privileged. Ensure:
- Service role keys are not pasted into Cursor chats.
- Service role keys are never baked into generated client code; Cursor should be instructed to use the anon key for client libraries and to leave service role usage to backend-only contexts.
Cost-aware environment strategies
The workflow scales from a low-cost solo setup to a multi-environment team configuration.
Solo on Supabase Free: dev + prod
Using Supabase’s Free plan:
- It is possible to have up to 2 active projects per account on Free at US$0 subscription cost, within the documented quota rules for organisations where the account is Owner or Admin.
- Each project’s Micro instance has a nominal cost of US$10/month, so dev + prod is approximately US$20/month in compute for two always-on Micro instances.
- Supabase’s billing docs state paused projects do not count towards the free project limit, so a project can be paused when idle and run only one project at a time if budget is tight, with compute charges stopping for the paused project.
The workflow is the same: Cursor MCP points at dev, migrations are committed, and an inexpensive manual step applies them to production if a full CI pipeline is not in place yet.
Small team on Supabase Pro: dev + staging + prod
On Pro:
- Organisation subscription: from US$25/month, including US$10/month in compute credits.
- Three Micro projects (dev, staging, prod) have a nominal compute cost of US$30; the credit offsets one Micro instance, so net compute is approximately US$20.
- Total baseline infra is therefore around US$45/month before storage, egress and any add-ons.
That buys a proper three-environment pipeline where every AI-assisted change runs through staging.
Heavier production workloads
Supabase’s compute configuration section shows higher instance sizes and optional add-ons, and the pricing page notes that Point in Time Recovery starts from US$100/month as a per-project add-on. A reasonable posture is:
- Keep dev and staging on Micro to minimise non-production cost.
- Size production according to traffic and latency needs.
- Use PITR on production for safety where justified by data value.
In this scenario, most of the bill comes from production; dev/staging remain relatively inexpensive and fully aligned with the Cursor + migrations workflow.
What changes the decision
The workflow above assumes Supabase is the primary database and that teams are willing to enforce Git- and PR-based governance. There are situations where the decision changes.
- Different primary database: If the stack is built on Neon, PlanetScale or Firebase, design a generic AI-assisted migration pipeline tailored to that provider’s tooling, or use a guide specific to that backend. Supabase’s project and RLS model is not directly portable. If you are comparing options, the Supabase vs Firebase comparison is a good place to start.
- No Git/PR discipline: If developers regularly run ad hoc SQL in production or commit directly to
main, no Cursor workflow will meaningfully reduce risk. Governance and PR workflows for AI coding agents need to come first.
- No RLS requirement: For purely internal tools on a private network or applications where data never hits untrusted clients, the loop can be simplified by dropping RLS design and testing, focusing solely on migrations and types.
- Budget too tight for staging: If the project cannot justify three environments, a dev + prod setup with aggressive pausing of dev is still workable. The core rule still holds: AI only touches dev; prod is driven by migrations.
Where to go next
For teams still evaluating backends, Supabase reviews and Supabase vs Firebase comparisons can inform the stack choice. For a deeper dive into constraining AI agents to PR-based workflows beyond databases, AI coding agent PR workflow writeups and Cursor rules articles offer broader patterns that can be layered onto this Supabase-specific migration loop. If you want to compare Cursor with other AI coding tools before standardising on this stack, the best AI coding tools shortlist and the dedicated Cursor review cover when this IDE-first approach makes sense relative to other agents.