React and Next.js performance optimization guidelines from Vercel Engineering...
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
Reference these guidelines when:
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Eliminating Waterfalls | CRITICAL | async- |
| 2 | Bundle Size Optimization | CRITICAL | bundle- |
| 3 | Server-Side Performance | HIGH | server- |
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | client- |
| 5 | Re-render Optimization | MEDIUM | rerender- |
| 6 | Rendering Performance | MEDIUM | rendering- |
| 7 | JavaScript Performance | LOW-MEDIUM | js- |
| 8 | Advanced Patterns | LOW | advanced- |
async-defer-await - Move await into branches where actually usedasync-parallel - Use Promise.all() for independent operationsasync-dependencies - Use better-all for partial dependenciesasync-api-routes - Start promises early, await late in API routesasync-suspense-boundaries - Use Suspense to stream contentbundle-barrel-imports - Import directly, avoid barrel filesbundle-no-self-barrel-import - Never import a layer's own barrel from inside that layer (Turbopack dynamic_imports.rs panic in route handlers / server actions)bundle-dynamic-imports - Use next/dynamic for heavy componentsbundle-defer-third-party - Load analytics/logging after hydrationbundle-conditional - Load modules only when feature is activatedbundle-preload - Preload on hover/focus for perceived speedserver-cache-react - Use React.cache() for per-request deduplicationserver-cache-lru - Use LRU cache for cross-request cachingserver-serialization - Minimize data passed to client componentsserver-parallel-fetching - Restructure components to parallelize fetchesserver-after-nonblocking - Use after() for non-blocking operationsclient-swr-dedup - Use SWR for automatic request deduplicationclient-event-listeners - Deduplicate global event listenersclient-scroll-container-listener - Subscribe to the actual scroll container, not window, when the app uses a custom scroll wrapperclient-tanstack-prefetch-key-match - Keep TanStack Query queryKey byte-identical between SSR prefetch and client hook to avoid silent hydration cache missclient-confirm-response-shape-before-refactor - Log Object.keys at the fetcher boundary to confirm backend response shape before updating TypeScript types; observed data over typed theory, single source of truth over dual fallbackclient-remove-legacy-fields-from-types-first - When a backend ships legacy + new fields during a transition, drop the legacy from client types immediately so the compiler enumerates every consumer; backend can drop the wire field only after the client provably stops reading itclient-cancel-recheck-after-await - In async polling/streaming loops, re-check the cancel flag after every await before any setState; loop-boundary checks alone let stale post-cancel responses overwrite cancelled statererender-defer-reads - Don't subscribe to state only used in callbacksrerender-memo - Extract expensive work into memoized componentsrerender-dependencies - Use primitive dependencies in effectsrerender-derived-state - Subscribe to derived booleans, not raw valuesrerender-derive-instead-of-mirror - Compute derived state at render; do not mirror it via useEffect+setState (avoids cascading-render anti-pattern flagged by react-hooks/set-state-in-effect)rerender-zustand-shallow-for-derived-selectors - Wrap Zustand selectors that build a new array/object (filter/map/Object.values) with useShallow; otherwise useSyncExternalStore's Object.is check loops foreverrerender-functional-setstate - Use functional setState for stable callbacksrerender-lazy-state-init - Pass function to useState for expensive valuesrerender-transitions - Use startTransition for non-urgent updatesrendering-animate-svg-wrapper - Animate div wrapper, not SVG elementrendering-content-visibility - Use content-visibility for long listsrendering-hoist-jsx - Extract static JSX outside componentsrendering-svg-precision - Reduce SVG coordinate precisionrendering-hydration-no-flicker - Use inline script for client-only datarendering-activity - Use Activity component for show/hiderendering-conditional-render - Use ternary, not && for conditionalsrendering-framer-motion-fixed-width - Animate Framer Motion width between fixed pixel values, not to "auto" (prevents spring jitter and first-render flicker)rendering-radix-popover-trigger-anchor - Anchor a controlled Radix Popover to its real trigger, never an empty placeholder (prevents detached popovers and skewed flex layouts)js-batch-dom-css - Group CSS changes via classes or cssTextjs-index-maps - Build Map for repeated lookupsjs-cache-property-access - Cache object properties in loopsjs-cache-function-results - Cache function results in module-level Mapjs-cache-storage - Cache localStorage/sessionStorage readsjs-combine-iterations - Combine multiple filter/map into one loopjs-length-check-first - Check array length before expensive comparisonjs-early-exit - Return early from functionsjs-hoist-regexp - Hoist RegExp creation outside loopsjs-min-max-loop - Use loop for min/max instead of sortjs-set-map-lookups - Use Set/Map for O(1) lookupsjs-tosorted-immutable - Use toSorted() for immutabilityadvanced-event-handler-refs - Store event handlers in refsadvanced-use-latest - useLatest for stable callback refsRead individual rule files for detailed explanations and code examples:
rules/async-parallel.md
rules/bundle-barrel-imports.md
rules/_sections.md
Each rule file contains:
For the complete guide with all rules expanded: AGENTS.md