[
{
"No": "1",
"Category": "Async Waterfall",
"Issue": "Defer Await",
"Keywords": "async await defer branch",
"Platform": "React/Next.js",
"Description": "Move await into branches where actually used to avoid blocking unused code paths",
"Do": "Move await operations into branches where they're needed",
"Don't": "Await at top of function blocking all branches",
"Code Example Good": "if (skip) return { skipped: true }; const data = await fetch()",
"Code Example Bad": "const data = await fetch(); if (skip) return { skipped: true }",
"Severity": "Critical"
},
{
"No": "2",
"Category": "Async Waterfall",
"Issue": "Promise.all Parallel",
"Keywords": "promise all parallel concurrent",
"Platform": "React/Next.js",
"Description": "Execute independent async operations concurrently using Promise.all()",
"Do": "Use Promise.all() for independent operations",
"Don't": "Sequential await for independent operations",
"Code Example Good": "const [user, posts] = await Promise.all([fetchUser(), fetchPosts()])",
"Code Example Bad": "const user = await fetchUser(); const posts = await fetchPosts()",
"Severity": "Critical"
},
{
"No": "3",
"Category": "Async Waterfall",
"Issue": "Dependency Parallelization",
"Keywords": "better-all dependency parallel",
"Platform": "React/Next.js",
"Description": "Use better-all for operations with partial dependencies to maximize parallelism",
"Do": "Use better-all to start each task at earliest possible moment",
"Don't": "Wait for unrelated data before starting dependent fetch",
"Code Example Good": "await all({ user() {}, config() {}, profile() { return fetch((await this.$.user).id) } })",
"Code Example Bad": "const [user, config] = await Promise.all([...]); const profile = await fetchProfile(user.id)",
"Severity": "Critical"
},
{
"No": "4",
"Category": "Async Waterfall",
"Issue": "API Route Optimization",
"Keywords": "api route waterfall promise",
"Platform": "React/Next.js",
"Description": "In API routes start independent operations immediately even if not awaited yet",
"Do": "Start promises early and await late",
"Don't": "Sequential awaits in API handlers",
"Code Example Good": "const sessionP = auth(); const configP = fetchConfig(); const session = await sessionP",
"Code Example Bad": "const session = await auth(); const config = await fetchConfig()",
"Severity": "Critical"
},
{
"No": "5",
"Category": "Async Waterfall",
"Issue": "Suspense Boundaries",
"Keywords": "suspense streaming boundary",
"Platform": "React/Next.js",
"Description": "Use Suspense to show wrapper UI faster while data loads",
"Do": "Wrap async components in Suspense boundaries",
"Don't": "Await data blocking entire page render",
"Code Example Good": "<Suspense fallback={<Skeleton />}><DataDisplay /></Suspense>",
"Code Example Bad": "const data = await fetchData(); return <DataDisplay data={data} />",
"Severity": "High"
},
{
"No": "6",
"Category": "Bundle Size",
"Issue": "Barrel Imports",
"Keywords": "barrel import direct path",
"Platform": "React/Next.js",
"Description": "Import directly from source files instead of barrel files to avoid loading unused modules",
"Do": "Import directly from source path",
"Don't": "Import from barrel/index files",
"Code Example Good": "import Check from 'lucide-react/dist/esm/icons/check'",
"Code Example Bad": "import { Check } from 'lucide-react'",
"Severity": "Critical"
},
{
"No": "7",
"Category": "Bundle Size",
"Issue": "Dynamic Imports",
"Keywords": "dynamic import lazy next",
"Platform": "React/Next.js",
"Description": "Use next/dynamic to lazy-load large components not needed on initial render",
"Do": "Use dynamic() for heavy components",
"Don't": "Import heavy components at top level",
"Code Example Good": "const Monaco = dynamic(() => import('./monaco'), { ssr: false })",
"Code Example Bad": "import { MonacoEditor } from './monaco-editor'",
"Severity": "Critical"
},
{
"No": "8",
"Category": "Bundle Size",
"Issue": "Defer Third Party",
"Keywords": "analytics defer third-party",
"Platform": "React/Next.js",
"Description": "Load analytics and logging after hydration since they don't block interaction",
"Do": "Load non-critical scripts after hydration",
"Don't": "Include analytics in main bundle",
"Code Example Good": "const Analytics = dynamic(() => import('@vercel/analytics'), { ssr: false })",
"Code Example Bad": "import { Analytics } from '@vercel/analytics/react'",
"Severity": "Medium"
},
{
"No": "9",
"Category": "Bundle Size",
"Issue": "Conditional Loading",
"Keywords": "conditional module lazy",
"Platform": "React/Next.js",
"Description": "Load large data or modules only when a feature is activated",
"Do": "Dynamic import when feature enabled",
"Don't": "Import large modules unconditionally",
"Code Example Good": "useEffect(() => { if (enabled) import('./heavy.js') }, [enabled])",
"Code Example Bad": "import { heavyData } from './heavy.js'",
"Severity": "High"
},
{
"No": "10",
"Category": "Bundle Size",
"Issue": "Preload Intent",
"Keywords": "preload hover focus intent",
"Platform": "React/Next.js",
"Description": "Preload heavy bundles on hover/focus before they're needed",
"Do": "Preload on user intent signals",
"Don't": "Load only on click",
"Code Example Good": "onMouseEnter={() => import('./editor')}",
"Code Example Bad": "onClick={() => import('./editor')}",
"Severity": "Medium"
},
{
"No": "11",
"Category": "Server",
"Issue": "React.cache Dedup",
"Keywords": "react cache deduplicate request",
"Platform": "React/Next.js",
"Description": "Use React.cache() for server-side request deduplication within single request",
"Do": "Wrap data fetchers with cache()",
"Don't": "Fetch same data multiple times in tree",
"Code Example Good": "export const getUser = cache(async () => await db.user.find())",
"Code Example Bad": "export async function getUser() { return await db.user.find() }",
"Severity": "Medium"
},
{
"No": "12",
"Category": "Server",
"Issue": "LRU Cache Cross-Request",
"Keywords": "lru cache cross request",
"Platform": "React/Next.js",
"Description": "Use LRU cache for data shared across sequential requests",
"Do": "Use LRU for cross-request caching",
"Don't": "Refetch same data on every request",
"Code Example Good": "const cache = new LRUCache({ max: 1000, ttl: 5*60*1000 })",
"Code Example Bad": "Always fetch from database",
"Severity": "High"
},
{
"No": "13",
"Category": "Server",
"Issue": "Minimize Serialization",
"Keywords": "serialization rsc boundary",
"Platform": "React/Next.js",
"Description": "Only pass fields that client actually uses across RSC boundaries",
"Do": "Pass only needed fields to client components",
"Don't": "Pass entire objects to client",
"Code Example Good": "<Profile name={user.name} />",
"Code Example Bad": "<Profile user={user} /> // 50 fields serialized",
"Severity": "High"
},
{
"No": "14",
"Category": "Server",
"Issue": "Parallel Fetching",
"Keywords": "parallel fetch component composition",
"Platform": "React/Next.js",
"Description": "Restructure components to parallelize data fetching in RSC",
"Do": "Use component composition for parallel fetches",
"Don't": "Sequential fetches in parent component",
"Code Example Good": "<Header /><Sidebar /> // both fetch in parallel",
"Code Example Bad": "const header = await fetchHeader(); return <><div>{header}</div><Sidebar /></>",
"Severity": "Critical"
},
{
"No": "15",
"Category": "Server",
"Issue": "After Non-blocking",
"Keywords": "after non-blocking logging",
"Platform": "React/Next.js",
"Description": "Use Next.js after() to schedule work after response is sent",
"Do": "Use after() for logging/analytics",
"Don't": "Block response for non-critical operations",
"Code Example Good": "after(async () => { await logAction() }); return Response.json(data)",
"Code Example Bad": "await logAction(); return Response.json(data)",
"Severity": "Medium"
},
{
"No": "16",
"Category": "Client",
"Issue": "SWR Deduplication",
"Keywords": "swr dedup cache revalidate",
"Platform": "React/Next.js",
"Description": "Use SWR for automatic request deduplication and caching",
"Do": "Use useSWR for client data fetching",
"Don't": "Manual fetch in useEffect",
"Code Example Good": "const { data } = useSWR('/api/users', fetcher)",
"Code Example Bad": "useEffect(() => { fetch('/api/users').then(setUsers) }, [])",
"Severity": "Medium-High"
},
{
"No": "17",
"Category": "Client",
"Issue": "Event Listener Dedup",
"Keywords": "event listener deduplicate global",
"Platform": "React/Next.js",
"Description": "Share global event listeners across component instances",
"Do": "Use useSWRSubscription for shared listeners",
"Don't": "Register listener per component instance",
"Code Example Good": "useSWRSubscription('global-keydown', () => { window.addEventListener... })",
"Code Example Bad": "useEffect(() => { window.addEventListener('keydown', handler) }, [])",
"Severity": "Low"
},
{
"No": "18",
"Category": "Rerender",
"Issue": "Defer State Reads",
"Keywords": "state read callback subscription",
"Platform": "React/Next.js",
"Description": "Don't subscribe to state only used in callbacks",
"Do": "Read state on-demand in callbacks",
"Don't": "Subscribe to state used only in handlers",
"Code Example Good": "const handleClick = () => { const params = new URLSearchParams(location.search) }",
"Code Example Bad": "const params = useSearchParams(); const handleClick = () => { params.get('ref') }",
"Severity": "Medium"
},
{
"No": "19",
"Category": "Rerender",
"Issue": "Memoized Components",
"Keywords": "memo extract expensive",
"Platform": "React/Next.js",
"Description": "Extract expensive work into memoized components for early returns",
"Do": "Extract to memo() components",
"Don't": "Compute expensive values before early return",
"Code Example Good": "const UserAvatar = memo(({ user }) => ...); if (loading) return <Skeleton />",
"Code Example Bad": "const avatar = useMemo(() => compute(user)); if (loading) return <Skeleton />",
"Severity": "Medium"
},
{
"No": "20",
"Category": "Rerender",
"Issue": "Narrow Dependencies",
"Keywords": "effect dependency primitive",
"Platform": "React/Next.js",
"Description": "Specify primitive dependencies instead of objects in effects",
"Do": "Use primitive values in dependency arrays",
"Don't": "Use object references as dependencies",
"Code Example Good": "useEffect(() => { console.log(user.id) }, [user.id])",
"Code Example Bad": "useEffect(() => { console.log(user.id) }, [user])",
"Severity": "Low"
},
{
"No": "21",
"Category": "Rerender",
"Issue": "Derived State",
"Keywords": "derived boolean subscription",
"Platform": "React/Next.js",
"Description": "Subscribe to derived booleans instead of continuous values",
"Do": "Use derived boolean state",
"Don't": "Subscribe to continuous values",
"Code Example Good": "const isMobile = useMediaQuery('(max-width: 767px)')",
"Code Example Bad": "const width = useWindowWidth(); const isMobile = width < 768",
"Severity": "Medium"
},
{
"No": "22",
"Category": "Rerender",
"Issue": "Functional setState",
"Keywords": "functional setstate callback",
"Platform": "React/Next.js",
"Description": "Use functional setState updates for stable callbacks and no stale closures",
"Do": "Use functional form: setState(curr => ...)",
"Don't": "Reference state directly in setState",
"Code Example Good": "setItems(curr => [...curr, newItem])",
"Code Example Bad": "setItems([...items, newItem]) // items in deps",
"Severity": "Medium"
},
{
"No": "23",
"Category": "Rerender",
"Issue": "Lazy State Init",
"Keywords": "usestate lazy initialization",
"Platform": "React/Next.js",
"Description": "Pass function to useState for expensive initial values",
"Do": "Use function form for expensive init",
"Don't": "Compute expensive value directly",
"Code Example Good": "useState(() => buildSearchIndex(items))",
"Code Example Bad": "useState(buildSearchIndex(items)) // runs every render",
"Severity": "Medium"
},
{
"No": "24",
"Category": "Rerender",
"Issue": "Transitions",
"Keywords": "starttransition non-urgent",
"Platform": "React/Next.js",
"Description": "Mark frequent non-urgent state updates as transitions",
"Do": "Use startTransition for non-urgent updates",
"Don't": "Block UI on every state change",
"Code Example Good": "startTransition(() => setScrollY(window.scrollY))",
"Code Example Bad": "setScrollY(window.scrollY) // blocks on every scroll",
"Severity": "Medium"
},
{
"No": "25",
"Category": "Rendering",
"Issue": "SVG Animation Wrapper",
"Keywords": "svg animation wrapper div",
"Platform": "React/Next.js",
"Description": "Wrap SVG in div and animate wrapper for hardware acceleration",
"Do": "Animate div wrapper around SVG",
"Don't": "Animate SVG element directly",
"Code Example Good": "<div class='animate-spin'><svg>...</svg></div>",
"Code Example Bad": "<svg class='animate-spin'>...</svg>",
"Severity": "Low"
},
{
"No": "26",
"Category": "Rendering",
"Issue": "Content Visibility",
"Keywords": "content-visibility auto",
"Platform": "React/Next.js",
"Description": "Apply content-visibility: auto to defer off-screen rendering",
"Do": "Use content-visibility for long lists",
"Don't": "Render all list items immediately",
"Code Example Good": ".item { content-visibility: auto; contain-intrinsic-size: 0 80px }",
"Code Example Bad": "Render 1000 items without optimization",
"Severity": "High"
},
{
"No": "27",
"Category": "Rendering",
"Issue": "Hoist Static JSX",
"Keywords": "hoist static jsx element",
"Platform": "React/Next.js",
"Description": "Extract static JSX outside components to avoid re-creation",
"Do": "Hoist static elements to module scope",
"Don't": "Create static elements inside components",
"Code Example Good": "const skeleton = <div class='animate-pulse' />; function C() { return skeleton }",
"Code Example Bad": "function C() { return <div class='animate-pulse' /> }",
"Severity": "Low"
},
{
"No": "28",
"Category": "Rendering",
"Issue": "Hydration No Flicker",
"Keywords": "hydration mismatch flicker",
"Platform": "React/Next.js",
"Description": "Use inline script to set client-only data before hydration",
"Do": "Inject sync script for client-only values",
"Don't": "Use useEffect causing flash",
"Code Example Good": "<script dangerouslySetInnerHTML={{ __html: 'el.className = localStorage.theme' }} />",
"Code Example Bad": "useEffect(() => setTheme(localStorage.theme), []) // flickers",
"Severity": "Medium"
},
{
"No": "29",
"Category": "Rendering",
"Issue": "Conditional Render",
"Keywords": "conditional render ternary",
"Platform": "React/Next.js",
"Description": "Use ternary instead of && when condition can be 0 or NaN",
"Do": "Use explicit ternary for conditionals",
"Don't": "Use && with potentially falsy numbers",
"Code Example Good": "{count > 0 ? <Badge>{count}</Badge> : null}",
"Code Example Bad": "{count && <Badge>{count}</Badge>} // renders '0'",
"Severity": "Low"
},
{
"No": "30",
"Category": "Rendering",
"Issue": "Activity Component",
"Keywords": "activity show hide preserve",
"Platform": "React/Next.js",
"Description": "Use Activity component to preserve state/DOM for toggled components",
"Do": "Use Activity for expensive toggle components",
"Don't": "Unmount/remount on visibility toggle",
"Code Example Good": "<Activity mode={isOpen ? 'visible' : 'hidden'}><Menu /></Activity>",
"Code Example Bad": "{isOpen && <Menu />} // loses state",
"Severity": "Medium"
},
{
"No": "31",
"Category": "JS Perf",
"Issue": "Batch DOM CSS",
"Keywords": "batch dom css reflow",
"Platform": "React/Next.js",
"Description": "Group CSS changes via classes or cssText to minimize reflows",
"Do": "Use class toggle or cssText",
"Don't": "Change styles one property at a time",
"Code Example Good": "element.classList.add('highlighted')",
"Code Example Bad": "el.style.width='100px'; el.style.height='200px'",
"Severity": "Medium"
},
{
"No": "32",
"Category": "JS Perf",
"Issue": "Index Map Lookup",
"Keywords": "map index lookup find",
"Platform": "React/Next.js",
"Description": "Build Map for repeated lookups instead of multiple .find() calls",
"Do": "Build index Map for O(1) lookups",
"Don't": "Use .find() in loops",
"Code Example Good": "const byId = new Map(users.map(u => [u.id, u])); byId.get(id)",
"Code Example Bad": "users.find(u => u.id === order.userId) // O(n) each time",
"Severity": "Low-Medium"
},
{
"No": "33",
"Category": "JS Perf",
"Issue": "Cache Property Access",
"Keywords": "cache property loop",
"Platform": "React/Next.js",
"Description": "Cache object property lookups in hot paths",
"Do": "Cache values before loops",
"Don't": "Access nested properties in loops",
"Code Example Good": "const val = obj.config.settings.value; for (...) process(val)",
"Code Example Bad": "for (...) process(obj.config.settings.value)",
"Severity": "Low-Medium"
},
{
"No": "34",
"Category": "JS Perf",
"Issue": "Cache Function Results",
"Keywords": "memoize cache function",
"Platform": "React/Next.js",
"Description": "Use module-level Map to cache repeated function results",
"Do": "Use Map cache for repeated calls",
"Don't": "Recompute same values repeatedly",
"Code Example Good": "const cache = new Map(); if (cache.has(x)) return cache.get(x)",
"Code Example Bad": "slugify(name) // called 100 times same input",
"Severity": "Medium"
},
{
"No": "35",
"Category": "JS Perf",
"Issue": "Cache Storage API",
"Keywords": "localstorage cache read",
"Platform": "React/Next.js",
"Description": "Cache localStorage/sessionStorage reads in memory",
"Do": "Cache storage reads in Map",
"Don't": "Read storage on every call",
"Code Example Good": "if (!cache.has(key)) cache.set(key, localStorage.getItem(key))",
"Code Example Bad": "localStorage.getItem('theme') // every call",
"Severity": "Low-Medium"
},
{
"No": "36",
"Category": "JS Perf",
"Issue": "Combine Iterations",
"Keywords": "combine filter map loop",
"Platform": "React/Next.js",
"Description": "Combine multiple filter/map into single loop",
"Do": "Single loop for multiple categorizations",
"Don't": "Chain multiple filter() calls",
"Code Example Good": "for (u of users) { if (u.isAdmin) admins.push(u); if (u.isTester) testers.push(u) }",
"Code Example Bad": "users.filter(admin); users.filter(tester); users.filter(inactive)",
"Severity": "Low-Medium"
},
{
"No": "37",
"Category": "JS Perf",
"Issue": "Length Check First",
"Keywords": "length check array compare",
"Platform": "React/Next.js",
"Description": "Check array lengths before expensive comparisons",
"Do": "Early return if lengths differ",
"Don't": "Always run expensive comparison",
"Code Example Good": "if (a.length !== b.length) return true; // then compare",
"Code Example Bad": "a.sort().join() !== b.sort().join() // even when lengths differ",
"Severity": "Medium-High"
},
{
"No": "38",
"Category": "JS Perf",
"Issue": "Early Return",
"Keywords": "early return exit function",
"Platform": "React/Next.js",
"Description": "Return early when result is determined to skip processing",
"Do": "Return immediately on first error",
"Don't": "Process all items then check errors",
"Code Example Good": "for (u of users) { if (!u.email) return { error: 'Email required' } }",
"Code Example Bad": "let hasError; for (...) { if (!email) hasError=true }; if (hasError)...",
"Severity": "Low-Medium"
},
{
"No": "39",
"Category": "JS Perf",
"Issue": "Hoist RegExp",
"Keywords": "regexp hoist module",
"Platform": "React/Next.js",
"Description": "Don't create RegExp inside render - hoist or memoize",
"Do": "Hoist RegExp to module scope",
"Don't": "Create RegExp every render",
"Code Example Good": "const EMAIL_RE = /^[^@]+@[^@]+$/; function validate() { EMAIL_RE.test(x) }",
"Code Example Bad": "function C() { const re = new RegExp(pattern); re.test(x) }",
"Severity": "Low-Medium"
},
{
"No": "40",
"Category": "JS Perf",
"Issue": "Loop Min Max",
"Keywords": "loop min max sort",
"Platform": "React/Next.js",
"Description": "Use loop for min/max instead of sort - O(n) vs O(n log n)",
"Do": "Single pass loop for min/max",
"Don't": "Sort array to find min/max",
"Code Example Good": "let max = arr[0]; for (x of arr) if (x > max) max = x",
"Code Example Bad": "arr.sort((a,b) => b-a)[0] // O(n log n)",
"Severity": "Low"
},
{
"No": "41",
"Category": "JS Perf",
"Issue": "Set Map Lookups",
"Keywords": "set map includes has",
"Platform": "React/Next.js",
"Description": "Use Set/Map for O(1) lookups instead of array.includes()",
"Do": "Convert to Set for membership checks",
"Don't": "Use .includes() for repeated checks",
"Code Example Good": "const allowed = new Set(['a','b']); allowed.has(id)",
"Code Example Bad": "const allowed = ['a','b']; allowed.includes(id)",
"Severity": "Low-Medium"
},
{
"No": "42",
"Category": "JS Perf",
"Issue": "toSorted Immutable",
"Keywords": "tosorted sort immutable",
"Platform": "React/Next.js",
"Description": "Use toSorted() instead of sort() to avoid mutating arrays",
"Do": "Use toSorted() for immutability",
"Don't": "Mutate arrays with sort()",
"Code Example Good": "users.toSorted((a,b) => a.name.localeCompare(b.name))",
"Code Example Bad": "users.sort((a,b) => a.name.localeCompare(b.name)) // mutates",
"Severity": "Medium-High"
},
{
"No": "43",
"Category": "Advanced",
"Issue": "Event Handler Refs",
"Keywords": "useeffectevent ref handler",
"Platform": "React/Next.js",
"Description": "Store callbacks in refs for stable effect subscriptions",
"Do": "Use useEffectEvent for stable handlers",
"Don't": "Re-subscribe on every callback change",
"Code Example Good": "const onEvent = useEffectEvent(handler); useEffect(() => { listen(onEvent) }, [])",
"Code Example Bad": "useEffect(() => { listen(handler) }, [handler]) // re-subscribes",
"Severity": "Low"
},
{
"No": "44",
"Category": "Advanced",
"Issue": "useLatest Hook",
"Keywords": "uselatest ref callback",
"Platform": "React/Next.js",
"Description": "Access latest values in callbacks without adding to dependency arrays",
"Do": "Use useLatest for fresh values in stable callbacks",
"Don't": "Add callback to effect dependencies",
"Code Example Good": "const cbRef = useLatest(cb); useEffect(() => { setTimeout(() => cbRef.current()) }, [])",
"Code Example Bad": "useEffect(() => { setTimeout(() => cb()) }, [cb]) // re-runs",
"Severity": "Low"
}
]