Browse 158 rules, 25 knowledge articles, and 25 prompt templates across security, performance, architecture, and quality.
158 rules
Raw <img> tags skip automatic optimization, lazy loading, and responsive sizing. next/image provides WebP/AVIF conversion, blur placeholders, and CLS prevention.
useEffect hooks that set up subscriptions, timers, or event listeners without cleanup cause memory leaks, stale state updates, and race conditions.
Each serverless invocation opening a direct database connection exhausts PostgreSQL's connection limit. Use Supavisor pooler URLs for all serverless environments.
Next.js has no built-in rate limiting. Without it, login, signup, password reset, and Server Actions are vulnerable to brute force and credential stuffing. [CWE-799, CWE-307 · A04:2021]
Barrel file imports in Client Components force bundlers to load entire libraries. Use direct imports or Next.js optimizePackageImports.
Inserting or updating rows one at a time in a loop creates N HTTP requests. Use .insert([...]) or .upsert([...]) to batch into a single request.
Logging OAuth tokens, API keys, passwords, or PII exposes secrets in log aggregation services and crash reporters. Use scoped loggers with sanitization. [CWE-532 · A09:2021]
Only add "use client" when a component needs hooks, event handlers, or browser APIs. Every unnecessary "use client" directive ships the component and all its dependencies to the browser as additional JavaScript — slowing down page loads, increasing bandwidth costs, and degrading the experience for users on slow connections or low-powered devices.
When the same logic appears in three or more places, extract it into a shared function, hook, or module. Duplicated code means that when you fix a bug or change behavior in one copy, the other copies silently remain broken — leading to inconsistent behavior, hard-to-trace bugs, and wasted time tracking down "why does it work here but not there."
Don't use useEffect to sync state that can be computed from existing state or props. Derived values should be calculated during render, not in effects. Effects for derived state cause extra renders, race conditions, and stale UI that flash incorrect data before correcting.
Always use stable, unique keys in array .map() renders. Missing or unstable keys (like array index) cause React to destroy and recreate DOM nodes, losing component state and causing visual glitches.
Database access belongs in repository classes, not in services or route handlers. Repositories abstract the data source behind a typed interface. [CWE-1057]
Adding 'use client' to large components or pages ships unnecessary JavaScript to the browser. Push interactivity to the smallest leaf components.
Using useEffect + useState for data fetching creates waterfalls, loading spinners, and unnecessary API routes. Use async Server Components instead.
Never use `any` as a type annotation. `any` disables all type checking for that value and everything it touches, spreading through your codebase like a virus — one `any` can silently disable type safety across dozens of files.
Using .range() offset pagination for large datasets forces PostgreSQL to scan all skipped rows. Use cursor-based pagination with .gt()/.lt() for constant-time page fetches.
Model mutually exclusive states with discriminated unions, not optional fields. Optional fields allow impossible states (e.g., `status: 'success'` with `error: 'failed'`) that compile but crash at runtime.
Using .select('*') fetches all columns including large text/json fields, wastes bandwidth, leaks data shape, and prevents index-only scans.
Add database indexes for columns used in WHERE, JOIN, and ORDER BY clauses. Without indexes, the database scans every row in the table for every query — a table with 1M rows takes seconds instead of milliseconds.
Schema changes via Supabase MCP, SQL editor, or dashboard don't create migration files. This causes schema drift between environments.
Define foreign key constraints for all table relationships. Without foreign keys, the database allows orphaned rows (e.g., an order referencing a deleted customer), corrupting data integrity silently.
Test what the code does (outputs, side effects), not how it does it (internal method calls, private state). Implementation-coupled tests break every time you refactor, even when behavior is unchanged — making tests a liability instead of a safety net.
Every test must be independent — no shared mutable state, no execution order dependencies. When tests share state, they pass in isolation but fail together (or worse, fail randomly), creating flaky CI that wastes hours of debugging time.
Use semantic HTML elements (<nav>, <main>, <article>, <button>) instead of generic <div> and <span> with click handlers. Screen readers and assistive technology rely on semantic elements to understand page structure — a <div onClick> looks like nothing to a blind user.
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.