Cursor rules for Next.js and Supabase: a working setup
If you build a Next.js and Supabase app with Cursor, the agent tends to repeat the same few mistakes. It creates tables without row-level security. It checks the session with the wrong call on the server. It reaches for a package that has been deprecated, or a file name from an older Next.js version. Project rules fix this by putting your conventions in front of the agent on every request. This guide shows how Cursor loads rules, a file layout that works, and three rules you can copy.
Checked on 27 Oct 2026 against Cursor's rules docs, the Next.js 16 docs and Supabase's server-side auth and Row Level Security docs. Next.js 16.4 is the current release; 15.5 still gets backports.
How Cursor loads rules
Project rules are .mdc files in .cursor/rules/. Cursor's docs are clear on two details that trip people up: the extension must be .mdc, and a plain .md file in that folder is ignored. Each file starts with frontmatter that decides when it loads.
| Frontmatter | Behaviour |
|---|---|
alwaysApply: true |
Included in every chat |
globs set, alwaysApply: false
|
Attached when a matching file is in context |
description only |
The agent reads the description and decides whether to pull the rule in |
| None of those | Only used when you @-mention the rule |
Cursor's own guidance is to keep each rule under 500 lines, split large rules into smaller ones, and avoid vague advice. Rules cost context on every request, so the always-on files should be short.
A layout that works
.cursor/rules/
00-core.mdc always on: stack, commands, how to work
10-supabase-auth.mdc attached to lib/supabase/**, proxy.ts, actions
20-database-rls.mdc attached to supabase/**
AGENTS.md the same core rules for other tools
Keep the always-on file small and move anything that only matters for one part of the code into a glob-scoped rule. The agent then sees Supabase guidance when it touches Supabase files and not when it is styling a button.
Rule 1: core conventions (always on)
---
description: Core conventions for Next.js App Router + Supabase
alwaysApply: true
---
- Check package.json for the installed next version before using an API.
- Default to Server Components. Add "use client" only to the smallest
component that needs state, effects or browser APIs.
- Mutations go through Server Actions or Route Handlers. Validate every
input with a schema (Zod) on the server.
- params, searchParams, cookies() and headers() are async: await them.
- Anything prefixed NEXT_PUBLIC_ is public. Secrets never go there.
- You are not done until typecheck, lint and build have run and you
have read the output.
The async line is real. Next.js 15 made these request APIs asynchronous with a temporary compatibility layer, and Next.js 16 removed synchronous access entirely, so old tutorial code fails on current versions.
Rule 2: Supabase auth on the server
---
description: Supabase clients and auth checks
globs: lib/supabase/**,proxy.ts,middleware.ts,app/**/actions.ts
alwaysApply: false
---
- Use @supabase/ssr: createBrowserClient in the browser,
createServerClient on the server, one factory per file in lib/supabase/.
- Cookie handling must implement getAll and setAll.
- On the server, identify the user with supabase.auth.getClaims().
Never trust supabase.auth.getSession() alone on the server.
- Use the publishable key in the browser. The secret key stays in
server-only code and is never in a NEXT_PUBLIC_ variable.
Supabase's docs say the same thing about getSession(): it reads the session from the cookie without revalidating it, and anyone can forge a cookie. getClaims() verifies the token's signature on each call. Use getUser() when you need an up-to-date user record from the Auth server.
Rule 3: Row Level Security
---
description: Migrations and Row Level Security
globs: supabase/**
alwaysApply: false
---
- Every table in an exposed schema gets RLS enabled, with explicit
policies, in the same migration that creates it.
- One policy per operation (select, insert, update, delete), each with
a "to" clause naming the role.
- Wrap helpers in a select: (select auth.uid()) = user_id.
- Update policies need both "using" and "with check".
- Never authorise from user_metadata. Users can edit it.
- Never disable RLS to make a query work. Fix the policy.
These lines come straight from the habits in Supabase's own guide: separate policies per operation, name the role with to, wrap auth.uid() in a select so Postgres can cache it, and keep authorisation data in app_metadata rather than user_metadata. For a fuller checklist, see our Supabase RLS checklist for AI-built apps.
Version traps worth writing down
-
middleware.ts became proxy.ts in Next.js 16. The function is named
proxyand runs on the Node.js runtime. Supabase's docs warn that on Next.js 15 and earlier aproxy.tsfile is never called, so sessions never refresh and users get signed out. Tell the agent which one your version uses. -
next lintis removed in Next.js 16. Run ESLint directly. -
Turbopack is the default bundler in Next.js 16. A custom webpack config makes
next buildfail unless you opt out.
Rules go stale. When the agent makes the same mistake twice, add a line. When you upgrade a major version, ask the agent to check the rules against the release notes.
Keep the files in sync
Cursor also reads AGENTS.md in the project root and in subfolders, which is useful if you switch tools. The cost is that you now maintain more than one file. The Vibemast Ship-It Kit handles that with a generator script: the rules are written once, and the script writes the Cursor rules, AGENTS.md, CLAUDE.md and Copilot instructions. It includes a full Next.js and Supabase rule set with the version traps above, plus 25 build prompts, 8 rescue prompts and a 20-point security audit. If you want to try the approach on one stack first, the free mini pack has the generator and a Vite and React rule set.
Before you ship a Next.js and Supabase app
Rules stop the agent writing unsafe code, but they do not check code that already exists. Before launch:
- Run the Supabase RLS checklist for AI-built apps on every table.
- Work through the Pre-launch security checklist for vibe-coded apps, especially secrets in
NEXT_PUBLIC_variables and payment webhooks. - Keep the same rules in
AGENTS.mdandCLAUDE.mdif anyone on the project uses Claude Code. See the Cursor rules vs CLAUDE.md vs AGENTS.md comparison.
The Ship-It Kit has the full Next.js and Supabase rule set (Cursor, Claude Code, Copilot and AGENTS.md versions, ready to copy) and 20 audit prompts that walk an agent through these checks one area at a time.
Who the paid kit is for, and who it is not for
- Worth it if you build on one of its four stacks (Next.js with Supabase, Vite with React, FastAPI, Phaser) and want tested files and prompts today instead of writing and testing your own.
- Not worth it if you only need one rules file for one project. The free guides and the free mini pack are enough, and you can adapt them yourself.
Related guides
FAQ
Where do Cursor rules go?
In .cursor/rules/ at the project root, as .mdc files. A .md file in that folder is ignored.
Should I use .cursorrules or .cursor/rules?
Use .cursor/rules. Cursor's current docs describe project rules in that folder and AGENTS.md as the simpler alternative. Older projects may still have a .cursorrules file; moving its content into rule files lets you scope it.
Why does Cursor ignore my rules?
Check the rule type first. A rule with alwaysApply: false and no description or globs only loads when you @-mention it. Also check the extension and the glob. If everything is set correctly, shorten the file: very long always-on rules compete with your prompt for attention.
Do rules replace Row Level Security?
No. Rules only make the agent more likely to write correct policies. Test them yourself with two accounts, or with supabase test db.