.claude/skills/vercel-react-best-practices/SKILL.md
React and Next.js performance optimization guidelines from Vercel Engineering. Use when writing, reviewing, or refactoring React/Next.js code. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
npx skillsauth add alfredolopez80/multi-agent-ralph-loop vercel-react-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
~/.claude/settings.json or CLI/env varsANTHROPIC_DEFAULT_*_MODEL env varsComprehensive performance optimization guide for React and Next.js applications from Vercel Engineering. Contains 45 rules across 8 categories, prioritized by impact.
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-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 listenersrerender-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-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 conditionalsjs-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 refsMove await operations into the branches where they're actually used to avoid blocking code paths that don't need them.
Incorrect: blocks both branches
async function handleRequest(userId: string, skipProcessing: boolean) {
const userData = await fetchUserData(userId)
if (skipProcessing) {
// Returns immediately but still waited for userData
return { skipped: true }
}
return processUserData(userData)
}
Correct: only blocks when needed
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
// Returns immediately without waiting
return { skipped: true }
}
const userData = await fetchUserData(userId)
return processUserData(userData)
}
For operations with partial dependencies, use better-all to maximize parallelism.
Incorrect: profile waits for config unnecessarily
const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
const profile = await fetchProfile(user.id)
Correct: config and profile run in parallel
import { all } from 'better-all'
const { user, config, profile } = await all({
async user() { return fetchUser() },
async config() { return fetchConfig() },
async profile() {
return fetchProfile((await this.$.user).id)
}
})
Import directly from modules instead of barrel files to enable better tree-shaking.
Incorrect: barrel file imports
import { Button, Input, Card, Modal } from '@/components'
Correct: direct imports
import Button from '@/components/Button'
import Input from '@/components/Input'
import Card from '@/components/Card'
import Modal from '@/components/Modal'
Use next/dynamic for heavy components that aren't needed on initial render.
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {
loading: () => <p>Loading...</p>,
ssr: false // Disable if no SSR needed
})
Use React.cache() to deduplicate calls within the same request.
import { cache } from 'react'
const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } })
})
// Both calls return the same promise within the same request
const user1 = await getUser('123')
const user2 = await getUser('123') // No additional database query
Use SWR for automatic request deduplication and caching.
import useSWR from 'swr'
function useUser(id: string) {
return useSWR(`/api/user/${id}`, fetcher)
}
Extract expensive work into memoized components to prevent unnecessary re-renders.
// Before: Expensive calculation on every render
function Dashboard({ data }) {
const summary = computeSummary(data) // Runs every render
return <div>{summary}</div>
}
// After: Memoized component
const Summary = memo(({ data }) => {
return <div>{computeSummary(data)}</div>
})
function Dashboard({ data }) {
return <Summary data={data} />
}
Use startTransition for non-urgent updates to keep the UI responsive.
import { useState, startTransition } from 'react'
function SearchResults({ query }) {
const [results, setResults] = useState([])
function handleChange(e) {
startTransition(() => {
setResults(search(e.target.value))
})
}
return <input onChange={handleChange} />
}
Version: 1.0.0 Author: Vercel Engineering License: MIT Reference: https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices
development
Living knowledge base management. Actions: search (query vault), save (store learning), index (update indices), compile (raw->wiki->rules graduation), init (create vault structure). Follows Karpathy pipeline: ingest->compile->query. Use when: (1) searching accumulated knowledge, (2) saving learnings, (3) compiling raw notes into wiki, (4) initializing a new vault. Triggers: /vault, 'vault search', 'knowledge base', 'save learning'.
testing
Produce a verifiable technical specification before coding. 6 mandatory sections: Interfaces, Behaviors, Invariants (from Aristotle Phase 2), File Plan, Test Plan, Exit Criteria (executable bash commands + expected results). Use when: (1) before implementing features with complexity > 4, (2) as Step 1.5 in orchestrator workflow, (3) when requirements need formalization. Triggers: /spec, 'create spec', 'write specification', 'technical spec'.
testing
Pre-launch shipping checklist orchestrating /gates, /security, /browser-test, /perf. Ensures nothing ships without passing all quality checks. Use when: (1) before deploying, (2) before merging to main, (3) before release. Triggers: /ship, 'ship it', 'ready to deploy', 'pre-launch check'.
development
Performance optimization skill. Core Web Vitals via Lighthouse, bundle size analysis, metrics tracking over time. Use when: (1) optimizing frontend performance, (2) analyzing bundle size, (3) tracking metrics regression. Triggers: /perf, 'performance audit', 'core web vitals', 'bundle size'.