REACT AND NEXT.JS performance optimization guidelines from Vercel Engineering. 70+ rules across 8 categories prioritized by impact. Enforce: no data waterfalls, no moment.js, no barrel imports, Server Components by default, TanStack Query for client fetching. Trigger: writing/reviewing/refactoring React or Next.js code, optimizing bundle size or load times.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
REACT AND NEXT.JS performance optimization guidelines from Vercel Engineering. 70+ rules across 8 categories prioritized by impact. Enforce: no data waterfalls, no moment.js, no barrel imports, Server Components by default, TanStack Query for client fetching. Trigger: writing/reviewing/refactoring React or Next.js code, optimizing bundle size or load times.
bundle-barrel-imports, Direct file paths, never barrel index files
bundle-dynamic-imports, next/dynamic for heavy components (charts, editors)
bundle-defer-third-party, Load analytics after hydration
bundle-conditional, Load modules only when feature activated
NEVER:
import { X } from '@/components', barrel imports
Synchronous <script> tags for third-party
import _ from 'lodash', tree-shake to lodash-es
Priority 3: Server-Side Performance
// ✅ Next.js 16, use cache directive for explicit cachingexportdefaultasyncfunctionPage() {
const data = awaitgetCachedData(); // uses React.cache() or 'use cache'
}
// ✅ Parallel fetch in RSCconst [user, posts] = awaitPromise.all([getUser(), getPosts()]);
ALWAYS:
server-hoist-static-io, Fonts, logos at module level
server-parallel-fetching, Promise.all() in RSC
server-cache-react, React.cache() for per-request dedup
server-dedup-props, Avoid duplicate serialization in props
server-auth-actions, Authenticate Server Actions like API routes
NEVER:
Module-level mutable request state in RSC/SSR
Passing entire DB objects to Client Components
Priority 4: Client-Side Data Fetching
// ✅ TanStack Query v5+, caching, dedup, retryconst { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
});
// ❌ Raw fetch(), no caching, no dedup, no retryconst [data, setData] = useState();
useEffect(() => { fetch('/api/users').then(setData); }, []);
ALWAYS: TanStack Query v5+ (useQuery, useMutation) for ALL client data
NEVER: Raw fetch() + useEffect for data fetching
NEVER:moment.js or date-fns, use Intl.DateTimeFormat
Priority 5: Re-render Optimization
// ✅ Memoize expensive componentsconstExpensiveChart = memo(functionExpensiveChart({ data }: { data: number[] }) {
// Expensive render work
});
// ✅ Functional setState for stable callbacksconst handleClick = useCallback(() => {
setCount(c => c + 1);
}, []); // No dependency on count
js-index-maps, Build Map for repeated array lookups
js-early-exit, Return early from functions
js-hoist-regexp, Hoist RegExp outside loops
js-combine-iterations, Combine filter/map into single loop
js-tosorted-immutable, Use .toSorted() for immutable sort
js-batch-dom-css, Group CSS changes via classes not individual style sets
Priority 8: Advanced Patterns
advanced-init-once, Initialize app once per load
advanced-use-latest, useLatest for stable callback refs
advanced-effect-event-deps, Don't put useEffectEvent results in deps
VALIDATE: Quality Gates
No data waterfalls: Independent fetches use Promise.all(). Sequential awaits on unrelated data prohibited
No moment.js/date-fns: Date formatting uses native Intl.DateTimeFormat. Zero date library deps
No barrel imports: Imports use direct file paths (e.g., @/components/Button), not @/components
Heavy components use dynamic import: Components with large bundles use next/dynamic + ssr: false
Third-party scripts deferred: Analytics, chat, external scripts use <Script strategy="lazyOnload">, never synchronous
Minimal client serialization: Server Components pass only required primitives to Client Components, never entire DB objects
Data fetching returns error states: Every hook returns isLoading + error. Every container handles both before success
Server deduplication: RSC data fetchers wrapped in React.cache() for per-request dedup
TanStack Query for client data: No raw fetch() in custom hooks, always useQuery/useMutation
No forwardRef: React 19.2, pass ref as normal prop (applicable to new code)
OUTPUT: What This Skill Produces
When applied, the skill categorizes each applicable rule into:
Applied: [rule-name], [what was changed]
Skipped: [rule-name], [why not applicable (e.g., "no third-party scripts in this page")]
Blocked: [rule-name], [what prevents applying it (e.g., "uses library X that requires barrel imports")]
AGENT BEHAVIOR: Mandatory Checks
Check for waterfalls, scan for sequential await on independent data. Combine with Promise.all().
Check date libs, find moment/date-fns imports → replace with Intl.DateTimeFormat
Check imports, find barrel imports → replace with direct file paths
Check heavy components, find large libs (charts, editors) not using dynamic → wrap in next/dynamic