react-best-practices
Original:🇺🇸 English
Not Translated
React and Next.js performance optimization guidelines from Vercel Engineering. Use when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
2installs
Added on
NPX Install
npx skill4agent add akillness/skills-template react-best-practicesSKILL.md Content
Vercel React Best Practices
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.
When to Apply
Reference these guidelines when:
- Writing new React components or Next.js pages
- Implementing data fetching (client or server-side)
- Reviewing code for performance issues
- Refactoring existing React/Next.js code
- Optimizing bundle size or load times
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Eliminating Waterfalls | CRITICAL | |
| 2 | Bundle Size Optimization | CRITICAL | |
| 3 | Server-Side Performance | HIGH | |
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | |
| 5 | Re-render Optimization | MEDIUM | |
| 6 | Rendering Performance | MEDIUM | |
| 7 | JavaScript Performance | LOW-MEDIUM | |
| 8 | Advanced Patterns | LOW | |
Quick Reference
1. Eliminating Waterfalls (CRITICAL)
- - Move await into branches where actually used
async-defer-await - - Use Promise.all() for independent operations
async-parallel - - Use better-all for partial dependencies
async-dependencies - - Start promises early, await late in API routes
async-api-routes - - Use Suspense to stream content
async-suspense-boundaries
2. Bundle Size Optimization (CRITICAL)
- - Import directly, avoid barrel files
bundle-barrel-imports - - Use next/dynamic for heavy components
bundle-dynamic-imports - - Load analytics/logging after hydration
bundle-defer-third-party - - Load modules only when feature is activated
bundle-conditional - - Preload on hover/focus for perceived speed
bundle-preload
3. Server-Side Performance (HIGH)
- - Use React.cache() for per-request deduplication
server-cache-react - - Use LRU cache for cross-request caching
server-cache-lru - - Minimize data passed to client components
server-serialization - - Restructure components to parallelize fetches
server-parallel-fetching - - Use after() for non-blocking operations
server-after-nonblocking
4. Client-Side Data Fetching (MEDIUM-HIGH)
- - Use SWR for automatic request deduplication
client-swr-dedup - - Deduplicate global event listeners
client-event-listeners
5. Re-render Optimization (MEDIUM)
- - Don't subscribe to state only used in callbacks
rerender-defer-reads - - Extract expensive work into memoized components
rerender-memo - - Use primitive dependencies in effects
rerender-dependencies - - Subscribe to derived booleans, not raw values
rerender-derived-state - - Use functional setState for stable callbacks
rerender-functional-setstate - - Pass function to useState for expensive values
rerender-lazy-state-init - - Use startTransition for non-urgent updates
rerender-transitions
6. Rendering Performance (MEDIUM)
- - Animate div wrapper, not SVG element
rendering-animate-svg-wrapper - - Use content-visibility for long lists
rendering-content-visibility - - Extract static JSX outside components
rendering-hoist-jsx - - Reduce SVG coordinate precision
rendering-svg-precision - - Use inline script for client-only data
rendering-hydration-no-flicker - - Use Activity component for show/hide
rendering-activity - - Use ternary, not && for conditionals
rendering-conditional-render
7. JavaScript Performance (LOW-MEDIUM)
- - Group CSS changes via classes or cssText
js-batch-dom-css - - Build Map for repeated lookups
js-index-maps - - Cache object properties in loops
js-cache-property-access - - Cache function results in module-level Map
js-cache-function-results - - Cache localStorage/sessionStorage reads
js-cache-storage - - Combine multiple filter/map into one loop
js-combine-iterations - - Check array length before expensive comparison
js-length-check-first - - Return early from functions
js-early-exit - - Hoist RegExp creation outside loops
js-hoist-regexp - - Use loop for min/max instead of sort
js-min-max-loop - - Use Set/Map for O(1) lookups
js-set-map-lookups - - Use toSorted() for immutability
js-tosorted-immutable
8. Advanced Patterns (LOW)
- - Store event handlers in refs
advanced-event-handler-refs - - useLatest for stable callback refs
advanced-use-latest
How to Use
For detailed explanations and code examples, read the full compiled document:
AGENTS.mdEach rule contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
Key Examples
Promise.all for Independent Operations (CRITICAL)
typescript
// ❌ Sequential: 3 round trips
const user = await fetchUser()
const posts = await fetchPosts()
const comments = await fetchComments()
// ✅ Parallel: 1 round trip
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])Avoid Barrel File Imports (CRITICAL)
tsx
// ❌ Imports entire library (200-800ms import cost)
import { Check, X, Menu } from 'lucide-react'
// ✅ Imports only what you need
import Check from 'lucide-react/dist/esm/icons/check'
import X from 'lucide-react/dist/esm/icons/x'Dynamic Imports for Heavy Components (CRITICAL)
tsx
// ❌ Monaco bundles with main chunk ~300KB
import { MonacoEditor } from './monaco-editor'
// ✅ Monaco loads on demand
import dynamic from 'next/dynamic'
const MonacoEditor = dynamic(
() => import('./monaco-editor').then(m => m.MonacoEditor),
{ ssr: false }
)Use Functional setState (MEDIUM)
tsx
// ❌ Requires state as dependency, stale closure risk
const addItems = useCallback((newItems) => {
setItems([...items, ...newItems])
}, [items])
// ✅ Stable callback, no stale closures
const addItems = useCallback((newItems) => {
setItems(curr => [...curr, ...newItems])
}, [])Constraints
Required Rules (MUST)
- Eliminate waterfalls: Use Promise.all, Suspense
- Bundle optimization: Prohibit barrel imports, use dynamic imports
- RSC boundaries: Serialize only the data you need
Prohibited (MUST NOT)
- Sequential await: Do not run independent fetches sequentially
- Array mutations: Use toSorted() instead of sort()
- Inline objects in React.cache: Causes cache misses
References
- React Documentation
- Next.js Documentation
- SWR
- better-all
- Vercel Blog: Optimizing Package Imports
- Vercel Blog: Dashboard Performance
Metadata
Version
- Current version: 1.0.0
- Last updated: 2026-01-22
- Supported platforms: Claude, ChatGPT, Gemini
- Source: vercel/agent-skills
Related Skills
- performance-optimization: General performance optimization
- state-management: State management
Tags
#React#Next.js#performance#optimization#vercel#waterfalls#bundle-size#RSC#frontend