

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# Full-Stack Next.js + Prisma + PostgreSQL + Tailwind — Cursor Rules2# End-to-end patterns for modern full-stack Next.js applications34# Project Context5You are building a full-stack web application with Next.js 14+ (App Router), Prisma ORM with6PostgreSQL, and Tailwind CSS. The project uses TypeScript throughout, Server Components for data7fetching, Server Actions for mutations, and follows full-stack best practices.89# Project Structure10```11src/12 app/13 (auth)/ # Auth route group (login, register)14 (dashboard)/ # Dashboard route group15 api/ # API routes (webhooks, external integrations only)16 layout.tsx17 page.tsx18 actions/ # Server Actions19 user.actions.ts20 project.actions.ts21 components/22 ui/ # Generic UI components (Button, Input, Card)23 forms/ # Form components with validation24 layouts/ # Layout components25 lib/26 db.ts # Prisma client singleton27 auth.ts # Auth utilities (NextAuth or custom)28 validations/ # Zod schemas29 utils.ts # Shared utilities30 types/ # TypeScript types (non-Prisma)31prisma/32 schema.prisma # Prisma schema33 migrations/ # Generated migrations34 seed.ts # Database seed script35```3637# Prisma Schema Patterns38- Use meaningful model names (singular, PascalCase): `User`, `Project`, `Comment`.39- Always define `createdAt` and `updatedAt` on every model:40```prisma41 model User {42 id String @id @default(cuid())43 email String @unique44 name String?45 role Role @default(USER)46 posts Post[]47 createdAt DateTime @default(now())48 updatedAt DateTime @updatedAt4950 @@index([email])51 @@map("users")52 }53```54- Use `cuid()` or `uuid()` for IDs — not auto-increment integers (security + distributed-friendly).55- Add `@@index` on fields used in WHERE clauses and foreign keys.56- Use enums for fixed sets of values: `enum Role { USER ADMIN MODERATOR }`.57- Use `@@map("table_name")` to control database table names (plural, snake_case).58- Use `@map("column_name")` for column name mapping when conventions differ.5960# Prisma Client Singleton61- Create a single Prisma client instance to avoid connection pool exhaustion:62```typescript63 // lib/db.ts64 import { PrismaClient } from '@prisma/client';6566 const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };67 export const prisma = globalForPrisma.prisma ?? new PrismaClient();68 if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;69```70- Import from `@/lib/db` everywhere — never create new `PrismaClient()` instances.7172# Data Fetching in Server Components73- Fetch data directly in Server Components using Prisma:74```typescript75 // app/dashboard/page.tsx76 import { prisma } from '@/lib/db';7778 export default async function DashboardPage() {79 const projects = await prisma.project.findMany({80 where: { userId: session.user.id },81 include: { tasks: { where: { completed: false } } },82 orderBy: { updatedAt: 'desc' },83 });84 return <ProjectList projects={projects} />;85 }86```87- Use `select` to fetch only needed fields (reduces data transfer).88- Use `include` sparingly — only load relations you actually render.89- DON'T: Create API routes to fetch data for your own pages — use Server Components.90- DON'T: Use Prisma on the client — it's server-only.9192# Server Actions for Mutations93- Define actions in dedicated files with `"use server"` directive:94```typescript95 // actions/project.actions.ts96 "use server";97 import { z } from 'zod';98 import { prisma } from '@/lib/db';99 import { revalidatePath } from 'next/cache';100101 const createProjectSchema = z.object({102 name: z.string().min(1).max(100),103 description: z.string().max(500).optional(),104 });105106 export async function createProject(formData: FormData) {107 const session = await getSession();108 if (!session) throw new Error('Unauthorized');109110 const parsed = createProjectSchema.safeParse({111 name: formData.get('name'),112 description: formData.get('description'),113 });114 if (!parsed.success) return { error: parsed.error.flatten() };115116 const project = await prisma.project.create({117 data: { ...parsed.data, userId: session.user.id },118 });119120 revalidatePath('/dashboard');121 return { data: project };122 }123```124- Always validate input with zod before database operations.125- Always verify authentication and authorization in every action.126- Use `revalidatePath()` after mutations to refresh cached data.127- Return structured results, not throw errors (for form state handling).128129# Tailwind CSS Patterns130- Use Tailwind utility classes directly in JSX.131- Extract repeated patterns into components, not CSS classes:132```typescript133 // DO: Create a reusable component134 function Card({ children }: { children: React.ReactNode }) {135 return <div className="rounded-lg border bg-white p-6 shadow-sm">{children}</div>;136 }137 // DON'T: @apply in CSS (defeats the purpose of utility-first)138```139- Use `cn()` utility (clsx + tailwind-merge) for conditional classes:140```typescript141 import { clsx, type ClassValue } from 'clsx';142 import { twMerge } from 'tailwind-merge';143 export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }144```145- Use Tailwind's `@screen` breakpoints: `sm:`, `md:`, `lg:`, `xl:`, `2xl:`.146- Design mobile-first: base styles for mobile, add breakpoint prefixes for larger screens.147148# Authentication Pattern149- Use NextAuth.js (Auth.js) or implement custom auth with JWT.150- Protect Server Components by checking session in the component:151```typescript152 const session = await getServerSession(authOptions);153 if (!session) redirect('/login');154```155- Protect Server Actions by verifying session at the start of every action.156- Store session data in a secure HttpOnly cookie.157- Use middleware.ts for route-level protection (redirect unauthenticated users).158159# Form Handling160- Use Server Actions with progressive enhancement:161```tsx162 <form action={createProject}>163 <input name="name" required />164 <SubmitButton />165 </form>166```167- Use `useFormState` and `useFormStatus` for client-side form state and pending UI.168- Show validation errors returned from Server Actions.169- Use optimistic updates with `useOptimistic` for better UX.170171# Database Migrations172- Run `npx prisma migrate dev --name descriptive-name` for development migrations.173- Run `npx prisma migrate deploy` in production (CI/CD).174- Never edit existing migrations — create new ones.175- Use `prisma db seed` for development data. Configure in package.json.176177# Performance178- Use Prisma's `select` to fetch only needed fields.179- Add database indexes for common query patterns.180- Use Next.js caching: `unstable_cache()` for database queries.181- Implement pagination for list queries — never load unbounded result sets.182- Use `<Suspense>` with loading.tsx for streaming SSR.183- Use `loading.tsx` at route segments for instant loading states.184185# Security186- Validate ALL input with zod at the Server Action boundary.187- Use parameterized queries (Prisma does this by default — never use `$queryRawUnsafe`).188- Implement rate limiting on sensitive actions (login, registration).189- Sanitize user-generated content before rendering.190- Use CSRF protection (Next.js Server Actions handle this automatically).191192# Testing193- Use Vitest for unit tests (faster than Jest with TypeScript).194- Test Server Actions by calling them directly with mock FormData.195- Use Playwright for E2E tests of critical flows.196- Use a test database with `prisma migrate reset` between test suites.197- Mock Prisma client for unit tests using `vitest-mock-extended`.198199# Common Mistakes to Avoid200- DON'T: Import Prisma client in Client Components — it only works server-side.201- DON'T: Create API routes for your own data fetching — use Server Components.202- DON'T: Skip input validation in Server Actions — forms can be submitted with any data.203- DON'T: Use `findFirst` without `where` — it returns a random record.204- DON'T: Forget `revalidatePath` after mutations — the UI won't update.205- DON'T: Store Prisma-generated types in your own types file — import from `@prisma/client`.206
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| survivorforge/cursor-rulesrules/ai-ml-python/.cursorrules · 17 | .cursorrules | teststylearchdeployment+2 | 81/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/api-microservices/.cursorrules · 17 | .cursorrules | buildteststylearch+5 | 92/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/database-sql/.cursorrules · 17 | .cursorrules | styletypessecuritydatabase+3 | 65/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/devops-docker/.cursorrules · 17 | .cursorrules | setupbuildteststyle+4 | 93/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/devops-infrastructure/.cursorrules · 17 | .cursorrules | buildteststylesecurity+3 | 93/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/django-rest/.cursorrules · 17 | .cursorrules | buildteststylearch+5 | 84/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/docker-devops/.cursorrules · 17 | .cursorrules | setupteststylearch+6 | 85/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/flutter-dart/.cursorrules · 17 | .cursorrules | teststylearchtypes+5 | 89/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/go-gin/.cursorrules · 17 | .cursorrules | testlint-formatstylearch+5 | 84/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/langchain-ai/.cursorrules · 17 | .cursorrules | testlint-formatstylearch+4 | 84/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/mobile-react-native/.cursorrules · 17 | .cursorrules | teststylearchtypes+7 | 89/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nextjs-14-app-router/.cursorrules · 17 | .cursorrules | teststyletypestesting-strategy+3 | 71/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nextjs-app-router/.cursorrules · 17 | .cursorrules | teststylearchtypes+5 | 81/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nextjs-typescript/.cursorrules · 17 | .cursorrules | teststylearchtypes+5 | 81/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nextjs/.cursorrules · 17 | .cursorrules | teststylearchtypes+5 | 81/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nodejs-express-typescript/.cursorrules · 17 | .cursorrules | setupteststylearch+7 | 81/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/nodejs-express/.cursorrules · 17 | .cursorrules | testlint-formatstylearch+7 | 92/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/performance-optimization/.cursorrules · 17 | .cursorrules | styledatabaseapiperformance+2 | 65/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/python-django/.cursorrules · 17 | .cursorrules | testlint-formatstylearch+6 | 99/100 | 13 days ago | |
| survivorforge/cursor-rulesrules/python-fastapi/.cursorrules · 17 | .cursorrules | testlint-formatstylearch+6 | 99/100 | 13 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/survivorforge-cursor-rules-rules-fullstack-nextjs-prisma-cursorrules)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.