Browse 158 rules, 25 knowledge articles, and 25 prompt templates across security, performance, architecture, and quality.
158 rules
Every <img> must have a meaningful alt attribute. Without alt text, screen readers either skip the image entirely or read the raw filename ("DSC_0042.jpg"), leaving visually impaired users completely unable to understand the content.
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.
Database access belongs in repository classes, not in services or route handlers. Repositories abstract the data source behind a typed interface. [CWE-1057]
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.
Raw <img> tags skip automatic optimization, lazy loading, and responsive sizing. next/image provides WebP/AVIF conversion, blur placeholders, and CLS prevention.
Text must meet WCAG AA contrast ratio: 4.5:1 for normal text, 3:1 for large text. Low-contrast text is unreadable for users with low vision, color blindness, or anyone using a screen in bright sunlight — affecting up to 8% of male users (color blindness alone).
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]
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.
Same logic duplicated in 3+ places creates consistency bugs and maintenance burden. Extract to the appropriate layer after the third occurrence.
Using 'any' or 'as any' at API boundaries, form handlers, and external data silently disables TypeScript safety, causing runtime crashes from unexpected data. [CWE-20]
useEffect hooks that set up subscriptions, timers, or event listeners without cleanup cause memory leaks, stale state updates, and race conditions.
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.
Pin exact versions for all dependencies in production (no ^, ~, or * ranges). Unpinned dependencies silently pull in new versions that can introduce breaking changes, security vulnerabilities, or performance regressions — and you won't know until production breaks.
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.
Next.js Server Actions rely on Origin header checks, not CSRF tokens. Reverse proxies and misconfigured allowedOrigins can bypass this protection. [CWE-352 · A01:2021]
Large client libraries loaded synchronously block the initial page load. Use next/dynamic or React.lazy to code-split and load them on demand.
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.
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.
Calling get_post_meta() inside loops without cache priming generates one database query per post. Use update_post_meta_cache or meta_query to batch lookups.
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."
External API calls, complex calculations, and aggregation queries should use set_transient/get_transient to avoid repeating expensive work on every page load.
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.
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]
State-changing API routes without CSRF validation allow cross-site request forgery. Validate tokens on POST/PUT/PATCH/DELETE with known exemptions. [CWE-352 · A01:2021]
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.