Browse 354 rules, 42 knowledge articles, and 28 prompt templates across security, performance, architecture, and quality.
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.
354 rules
API routes without rate limiting enable brute force, DDoS, and credit exhaustion attacks. Apply tiered rate limits as the first middleware. [CWE-770 · A04:2021]
Returning raw error messages or stack traces leaks implementation details. Return generic messages with a requestId for server-side debugging. [CWE-209]
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]
Inconsistent error handling with thrown exceptions, returned nulls, and ad-hoc error objects makes callers fragile. Use a discriminated union ServiceResult type.
Creating new components or utilities without checking if one already exists leads to duplicated logic and inconsistency. Search existing code first.
Bare console.log statements with no context make production debugging impossible. Use scoped loggers with errorId, userId, and structured metadata.
Same logic duplicated in 3+ places creates consistency bugs and maintenance burden. Extract to the appropriate layer after the third occurrence.
Using useEffect + useState for data fetching creates waterfalls, loading spinners, and unnecessary API routes. Use async Server Components instead.
Pages that block until all data loads show nothing until everything is ready. Wrap slow components in Suspense to stream content progressively.
Serial await statements for independent data fetches create request waterfalls. Use Promise.all to parallelize and cut load times by 2-5x.
Adding 'use client' to large components or pages ships unnecessary JavaScript to the browser. Push interactivity to the smallest leaf components.
Business logic belongs in service classes, not in route handlers, server actions, or components. Use the ServiceResult<T> pattern. [CWE-1086]
Database access belongs in repository classes, not in services or route handlers. Repositories abstract the data source behind a typed interface. [CWE-1057]
Split large repository interfaces into focused, role-specific contracts so consumers only depend on the methods they use
Use factory classes (ServiceFactory, RepositoryFactory) for dependency wiring instead of direct instantiation or imports in consuming code.
Domain entities should be pure TypeScript classes/interfaces with no framework dependencies like Supabase, React, or Next.js
Build in dependency order: Domain, Interface, Repository, Service, Controller, Presentation. Top-down builds couple UI to data.
When the same combination of Tailwind utilities appears in 3+ places, extract it to a component or @apply directive. Duplicated utility strings mean a design change (like spacing or color) requires finding and updating every copy — miss one and you have an inconsistent UI.
Always log errors with structured context: user ID, request ID, input data, stack trace. An error message like "Cannot read property of undefined" with no context is impossible to debug — you don't know which user hit it, what they were doing, or how to reproduce it.
Wrap UI sections in React Error Boundaries to catch rendering errors gracefully. Without error boundaries, a single component crash (a null reference, a failed API parse) takes down the entire page — showing users a white screen with no way to recover or navigate away.
Audit and minimize third-party scripts (analytics, chat widgets, ad trackers). Each third-party script adds DNS lookups, TLS handshakes, and JavaScript execution that blocks the main thread — a single chat widget can add 500ms+ to page load and degrade Core Web Vitals scores.
Serve images in modern formats (WebP/AVIF), at appropriate dimensions, and with width/height attributes. Unoptimized images are typically the largest assets on a page — a single uncompressed hero image can be larger than all your JavaScript combined, destroying load times on mobile.
Lazy-load images, components, and data that are below the initial viewport fold. Loading everything upfront makes the user wait for content they haven't scrolled to yet — increasing Time to Interactive and burning mobile data on content the user may never see.
Never merge user-controlled objects into application objects using Object.assign, spread, or deep-merge without validation. Prototype pollution lets an attacker inject __proto__ properties that modify the behavior of every object in your application — enabling denial of service, authentication bypass, or remote code execution.