Comprehensive Rules for high-quality, secure, and maintainable TypeScript codebases built with React & Next.js.
Your codebase doesn't have to be a maintenance nightmare. These Cursor Rules transform scattered development practices into a unified, production-ready workflow that catches bugs before they ship and keeps technical debt from accumulating.
You know the drill: spending 30 minutes hunting down a bug caused by an unvalidated API response, debugging type errors that should have been caught at compile time, or reviewing pull requests that require complete rewrites because everyone has different ideas about "good code."
These issues compound. What starts as "quick and dirty" becomes the foundation that breaks when you need to scale, onboard new developers, or meet security compliance requirements.
This rule set establishes enterprise-grade patterns for TypeScript applications that eliminate the most common sources of bugs, security vulnerabilities, and maintenance overhead:
Type Safety That Actually Works
Production-Ready Architecture
Security by Default
// Typical unvalidated API handler
export async function POST(request: Request) {
const body = await request.json();
const user = await db.user.create(body); // Hope body is valid!
return Response.json(user);
}
// Validated, typed, error-handled
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1)
});
export async function POST(request: Request) {
try {
const body = CreateUserSchema.parse(await request.json());
const user = await db.user.create(body);
return Response.json({ status: "success", data: user });
} catch (error) {
return handleApiError(error);
}
}
Time Saved: 2-3 hours per week on debugging validation issues, security reviews pass on first attempt, zero production errors from malformed data.
Before: 2-3 weeks to understand project conventions, frequent PR rejections for style inconsistencies, confusion about folder structure and testing patterns.
After: New developers productive in 3-5 days with clear conventions, automated formatting eliminates style discussions, predictable file locations reduce cognitive load.
Before: 45-60 minutes per PR reviewing style, architecture, and catching basic errors.
After: 15-20 minutes per PR focused on business logic, with automated checks handling consistency and security.
Save the complete rule set as .cursor-rules in your project root. Cursor AI will immediately start applying these patterns to all generated code.
// tsconfig.json additions
{
"compilerOptions": {
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true
}
}
# .github/workflows/quality.yml
- name: Type Check
run: npm run type-check
- name: Lint
run: npm run lint
- name: Test Coverage
run: npm run test -- --coverage --threshold=90
- name: Security Scan
run: npx snyk test --severity-threshold=high
src/
├─app/ # Next.js routes with Server Components
├─components/ # Reusable UI components
├─features/ # Feature-sliced business logic
├─lib/ # Pure utility functions
├─types/ # Shared TypeScript definitions
└─tests/ # End-to-end test suites
Week 1: Immediate reduction in basic TypeScript errors, consistent code formatting across the team.
Week 2-4: Faster code reviews, fewer bugs reaching staging, new developers contributing meaningfully.
Month 2+: 40-60% reduction in production bugs, security compliance achieved automatically, development velocity increases as technical debt decreases.
Long-term: Scalable codebase that handles team growth, regulatory requirements, and feature complexity without architectural rewrites.
Error Handling That Actually Helps
// Result pattern for pure functions
type Result<T, E> = { success: true; data: T } | { success: false; error: E };
export function parseUserInput(input: string): Result<User, ValidationError> {
// Implementation that never throws
}
Performance-First Component Loading
// Automatic code splitting for heavy components
const DataVisualization = dynamic(() => import('./data-viz'), {
ssr: false,
loading: () => <ChartSkeleton />
});
Security-Conscious Environment Management
// Validated configuration at startup
const ConfigSchema = z.object({
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32)
});
export const config = ConfigSchema.parse(process.env);
These rules don't just improve code quality—they transform how your team thinks about building applications. You'll catch issues before they become problems, ship features with confidence, and spend more time building than debugging.
Ready to eliminate the chaos? Copy these rules into your project and watch your development workflow transform from reactive firefighting to proactive, predictable software delivery.
You are an expert in TypeScript (ES2023), React 18, Next.js 14 (app router), Node.js 20, Jest, Playwright, ESLint, Prettier, GitHub Actions, Docker, and Snyk.
Key Principles
- Treat every file as a public API; keep surface area minimal.
- Prefer immutability, expressions over statements, and pure functions.
- Single Responsibility at every level: variable ↔ function ↔ module ↔ service.
- Self-explanatory code over comments. Comment only *why*, never *what*.
- Descriptive naming: <verb><noun> for functions (e.g., fetchUser), <noun> for data (e.g., userList).
- Avoid magic values; extract to readonly consts or env vars.
- Early-return error branches, happy path last.
- Composition over inheritance; HOCs / hooks over class components.
- "Fail fast, fail loud"—throw typed errors, log centrally, recover at boundaries.
- Zero warnings in ESLint, 100 % format compliance with Prettier.
TypeScript Rules
- Enable "strict", "exactOptionalPropertyTypes", "noUncheckedIndexedAccess" in tsconfig.
- Use type-annotated function signatures; infer inside body only.
- Prefer interfaces for public shapes, type aliases for unions & utility types.
- No implicit any, no namespaces, no /// <reference>.
- Enum ➞ never; use union literals.
- File naming: kebab-case; test files *.spec.ts(x); stories *.stories.tsx.
- Folder schema:
src/
├─app/ (Next.js routes)
├─components/ (reusable UI)
├─features/ (feature-sliced structure)
├─lib/ (pure helpers, no side-effects)
├─types/ (shared TypeScript types only)
└─tests/ (e2e & integration)
Example pure helper:
```ts
// src/lib/parse-int.ts
export function parseIntSafe(value: string): number | null {
const n = Number.parseInt(value, 10);
return Number.isNaN(n) ? null : n;
}
```
Error Handling & Validation
- All external boundaries (API, DB, env, browser storage) must validate input with Zod.
- Wrap async/await in try/catch; rethrow custom `AppError` subclasses with `kind` field.
- Never return null/undefined to signal errors; use `Result<T, E>` pattern in pure logic.
- Add exhaustive `default` in switch / discriminated union handling.
- Central error handler: `src/app/api/error.ts` captures, logs (Pino), and returns uniform JSON:
`{ status: "error", message, code }`.
Next.js Rules
- Only React Server Components (RSC) in `app/` unless client interactivity needed; mark with `'use client'` pragma.
- Use Next.js 14 `route.ts` file-based API routes with typed request schema.
- Generate metadata via static `generateMetadata` when possible to keep edge optimized.
- Fetch data in server components with `cache: 'force-cache'` unless dynamic.
- Handle errors with `error.tsx` and `not-found.tsx` conventions.
- Use `next/font` for local & Google fonts; no external <link> tags.
- Images: `<Image>` with `fill` prop, `sizes` attribute.
- State: global ➞ Zustand; local ➞ React useState/useReducer.
- CSS: Tailwind v3; extend via `@apply`, avoid custom CSS files.
Testing
- Apply TDD: write failing Jest unit test before implementation.
- Coverage threshold: lines ≥ 90 %, branches ≥ 80 % (enforced in CI).
- Use React Testing Library for DOM; no enzyme.
- Playwright for e2e; run against prod-like Docker compose stack.
- Mock only network & time; never components.
Example Jest pattern:
```ts
it("returns null on invalid input", () => {
expect(parseIntSafe("abc")).toBeNull();
});
```
Performance
- Avoid unnecessary client JS: keep bundle < 200 kB gzipped.
- Prefer edge runtime (`export const runtime = 'edge'`) for low-latency endpoints.
- Async import heavy libs: `const Chart = dynamic(() => import('./chart'), { ssr: false })`.
- Memoize expensive selectors with `useMemo`/`useCallback`; no blind memoization.
Security
- All env secrets through Next.js `process.env`, validated by Zod at boot.
- Enable `Content-Security-Policy`, `Strict-Transport-Security`, `X-Frame-Options` via `next.config.js` headers.
- Use Snyk scan in CI; build fails on high severity issues.
- Never log PII; mask using Pino redact.
Tooling & Automation
- Pre-commit: `lint-staged` runs `eslint --fix` & `prettier --write`.
- Commit messages follow Conventional Commits (`feat:`, `fix:`, etc.).
- GitHub Actions: build, test, type-check, lint, security scan, deploy.
jobs:
build ➞ type-check ➞ unit-test ➞ e2e-test ➞ snyk-scan ➞ deploy.
- Automatic version bump & changelog via `semantic-release` on main branch.
Documentation
- Each exported function/type requires `@example` JSDoc.
- ADRs stored in `/docs/adr/` following MADR template.
- Storybook documents every UI component with controls.
Common Pitfalls & Guards
- No `any` or `ts-ignore` in main code; allowed only inside tests with justification comment.
- Side-effect free modules—if side-effects needed, suffix file with `.bootstrap.ts`.
- Avoid date math with native Date; use `date-fns` + UTC.
- Prefer `Promise.allSettled` to parallelize multiple independent async tasks.