Skip to main content
rule

nextjs15-supabase-cursorrules — Cursor rule: 27 architecture bans

A Cursor rule that keeps the agent inside a Next.js 15, Supabase and TypeScript strict stack — from session checks to RLS and Stripe keys.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/nextjs15-supabase-cursorrules-prompt-file.mdc
Open on GitHub

What nextjs15-supabase-cursorrules-prompt-file does

The file lays out 27 rules for a project on Next.js 15 (App Router) with React 19, Supabase, Tailwind CSS and shadcn/ui. The agent reads them before writing code and is told to follow every rule unconditionally.

Among the bans: calling getSession() on the server instead of getUser(), touching params and searchParams synchronously, importing from the deprecated @supabase/auth-helpers-nextjs, tables without RLS, Stripe keys starting with sk_ in NEXT_PUBLIC_ variables, the any type, and auth enforcement inside middleware. Mutations must go through Server Actions with Zod validation and an ActionResponse<T> return, and every data-fetching page needs sibling loading.tsx and error.tsx files.

Code samples are included — a correct and a wrong version for each of the ten rules spelled out in the file. The full set of 27 lives separately in the vibestackdev/vibe-stack repository and installs with npx vibe-stack-rules init. If your project is not on Supabase, or you have already moved auth elsewhere, some of these bans will fight your existing code — worth checking which rules actually apply.

What it helps with

  • catch a server-side getSession() call before it ships
  • remember to await params and searchParams in Next.js 15
  • turn on RLS for every Supabase table
  • drop any and keep TypeScript strict
  • keep an sk_ Stripe key out of NEXT_PUBLIC_

Example prompts for the agent

  • Add a product page: read id from params with await and fetch the row from Supabase.
  • Write a Server Action that creates a record with Zod validation and a getUser() check.
  • Review my code for violations of the Next.js 15 and Supabase rules in this file.

How to install nextjs15-supabase-cursorrules-prompt-file

Manually: put the files in place

.cursor/rules/nextjs15-supabase-cursorrules-prompt-file.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about nextjs15-supabase-cursorrules-prompt-file

How do I install nextjs15-supabase-cursorrules in Cursor?

Place the file at .cursor/rules/nextjs15-supabase-cursorrules-prompt-file.mdc in your project root. Cursor picks it up as a rule.

What does this rule do?

It gives the agent 27 architecture constraints for a Next.js 15, Supabase and TypeScript strict stack: session verification, async params, RLS, Server Actions, Stripe keys.

Where is the full set of 27 rules?

The file points to the vibestackdev/vibe-stack repository and the npx vibe-stack-rules init command for a quick install.

Source text

nextjs15-supabase-cursorrules-prompt-file.mdc · CC0-1.0
---
description: "27 architecture rules preventing AI hallucinations: insecure auth (getSession vs getUser), synchronous params, deprecated imports, missing RLS, and Stripe key exposure. Built for Cursor Agent and Claude Code."
globs: **/*
alwaysApply: false
---
# Next.js 15 + Supabase Architecture Rules

You are an expert Next.js 15 developer working with Supabase, TypeScript (strict), and shadcn/ui.
Follow ALL rules below unconditionally. If you are tempted to deviate, re-read the rule.

## Tech Stack
- Framework: Next.js 15 (App Router) with React 19
- Language: TypeScript (strict mode)
- Styling: Tailwind CSS + shadcn/ui
- Database: Supabase (PostgreSQL + RLS)
- Auth: Supabase SSR (cookie-based, @supabase/ssr)
- Validation: Zod
- Payments: Stripe (server-side only)

## RULE 1: NEVER use getSession() on the server

SECURITY CRITICAL. getSession() reads the JWT from cookies WITHOUT verifying it.
A forged cookie passes silently. ALWAYS use getUser() for server-side auth.

```typescript
// ✅ CORRECT — verified with Supabase auth server
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/login')

// ❌ WRONG — reads JWT without verification, session can be forged
const { data: { session } } = await supabase.auth.getSession()
```

## RULE 2: NEVER access params synchronously in Next.js 15

In Next.js 15, params and searchParams are Promises. Synchronous access compiles
but crashes at runtime.

```typescript
// ✅ CORRECT
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
}

// ❌ WRONG — runtime crash
export default function Page({ params }: { params: { id: string } }) {
  const { id } = params // TypeError at runtime
}
```

## RULE 3: NEVER import from @supabase/auth-helpers-nextjs

This package is deprecated. It does NOT work with Next.js 15 App Router cookies.
ALWAYS use @supabase/ssr with manual cookie handling.

```typescript
// ✅ CORRECT
import { createServerClient } from '@supabase/ssr'

// ❌ WRONG — deprecated, broken with App Router
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
```

## RULE 4: All database tables MUST have RLS enabled

Every Supabase table must have Row Level Security enabled. Without RLS, any
user with the anon key can read ALL data from the table.

```sql
-- ✅ Always add after CREATE TABLE:
ALTER TABLE public.my_table ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can only read their own data"
  ON public.my_table FOR SELECT
  USING (auth.uid() = user_id);
```

## RULE 5: Default to Server Components

Only add 'use client' when the component needs interactivity (event handlers,
useState, useEffect). Push 'use client' to the smallest leaf component possible.

## RULE 6: All mutations via Server Actions

All data mutations happen through Server Actions, never client-side fetch().
Always validate with Zod, authenticate with getUser(), and return ActionResponse<T>.

```typescript
'use server'
import { z } from 'zod'

type ActionResponse<T = void> =
  | { success: true; data: T }
  | { success: false; error: string }

const Schema = z.object({ title: z.string().min(1).max(200) })

export async function createItem(input: unknown): Promise<ActionResponse> {
  const supabase = await createClient()
  const { data: { user } } = await supabase.auth.getUser()
  if (!user) return { success: false, error: 'Unauthorized' }

  const result = Schema.safeParse(input)
  if (!result.success) return { success: false, error: 'Invalid input' }

  const { error } = await supabase.from('items').insert({ ...result.data, user_id: user.id })
  if (error) return { success: false, error: 'Failed to create item' }

  revalidatePath('/items')
  return { success: true, data: undefined }
}
```

## RULE 7: Error boundaries for every data-fetching page

Every page that fetches data MUST have sibling loading.tsx and error.tsx files.

## RULE 8: NEVER expose Stripe secret keys

Stripe keys starting with `sk_` must NEVER be in NEXT_PUBLIC_ variables.
Use process.env.STRIPE_SECRET_KEY (server-only).

## RULE 9: TypeScript strict mode, no `any`

NEVER use `any`. Use `unknown` with Zod validation or type narrowing.
tsconfig.json MUST have `strict: true`.

## RULE 10: Middleware is for session REFRESH only

NEVER put auth enforcement in Next.js middleware. Middleware runs on Edge Runtime
and cannot verify Supabase JWTs. Auth enforcement belongs in layouts/pages with getUser().

---

Full rule set (27 rules) available at: https://github.com/vibestackdev/vibe-stack
Quick install: npx vibe-stack-rules init

© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules

Similar IDE rules

Everything for Security →

From the same set68

pyspark-etl-best-practices-cursorrules-prompt-file A Cursor rule that sets PySpark code style: F.col(), explicit joins, select over withColumn, and Iceberg-aware ETL structure. ★ 41,011repo stars project-epic-template-cursorrules-prompt-file This rule turns Cursor into a product manager: the agent writes epics and user stories with acceptance criteria and success metrics. ★ 41,011repo stars playwright-defect-tracking-cursorrules-prompt-file A Cursor rule that makes the agent write Playwright tests tied to manual case IDs, with screenshots and logs as defect evidence. ★ 41,011repo stars plasticode-telegram-api-cursorrules-prompt-file A Cursor rule that points the assistant at PHP 7.4, Plasticode and the Telegram Bot API. Useful when your bot is built on Plasticode and you want PSR-12 code. ★ 41,011repo stars nextjs-vercel-typescript-cursorrules-prompt-file A Cursor rule that sets code style and file structure for Next.js projects with TypeScript, Vercel middleware and a KV database. ★ 41,011repo stars nextjs-typescript-cursorrules-prompt-file A Cursor rule that pins the Next.js and TypeScript stack and the agent's working order: plan first, one file at a time, fixed reply format. ★ 41,011repo stars nextjs-tailwind-typescript-apps-cursorrules-prompt A Cursor rule that points the assistant at Next.js, Tailwind CSS and TypeScript. It sets the working order: plan in pseudocode first, code after. ★ 41,011repo stars nextjs-react-typescript-cursorrules-prompt-file A Cursor rule that tells the agent how to write code in Next.js 14 App Router, React and TypeScript projects. ★ 41,011repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor