Vercel React Best Practices
Overview
This skill curates the upstream react-best-practices workflow into an operator-ready execution path for React and Next.js performance work.
Keep the original intent: improve performance without cargo-cult optimizations, preserve provenance, and stay aligned with modern React and Next.js guidance. The upgraded workflow adds sharper activation boundaries, App Router vs Pages Router decision points, measurable validation, and compact local support files that help operators inspect a repository and document safe remediation.
Use this skill for performance-sensitive work in React or Next.js when the task involves one or more of these concerns:
- route or component slowness
- excessive client-side JavaScript
- cache or revalidation confusion
- hydration mismatch risk
- image, font, or third-party script regressions
- code review of React or Next.js performance changes
- performance validation before deploy or handoff
Ask one clarifying question before changing code if any of these are unclear:
- Is this App Router or Pages Router?
- Is the problem seen locally, in preview, or in production?
- Is the target symptom slow initial load, slow navigation, stale data, hydration mismatch, or poor Core Web Vitals?
When to Use This Skill
Activate this skill when the request is primarily about React or Next.js performance behavior, rendering strategy, loading behavior, or cache-aware delivery.
Good fit
- Writing or refactoring Next.js pages, layouts, or route segments with performance goals
- Reviewing
use client boundaries or deciding what should stay server-side
- Fixing slow LCP, CLS, INP, hydration mismatch, or bundle growth
- Reviewing image, font, script, or lazy-loading decisions
- Investigating stale data caused by caching or revalidation assumptions
- Preparing a performance-focused PR review, deployment review, or handoff note
Usually not the right skill
- Pure styling or design-system work with no performance concern
- Accessibility audits as the main objective
- Security reviews unrelated to frontend performance behavior
- CI/CD pipeline design unrelated to frontend build or deploy verification
- Generic React bugs with no rendering, loading, or cache dimension
If the request drifts into testing strategy, accessibility, security hardening, or deployment platform design, hand off to a more specific skill after capturing any performance findings already confirmed.
Operating Table
| Situation |
Start here |
Why it matters |
| You do not know the routing model |
Inspect for app/ vs pages/, then open references/nextjs-performance-guardrails.md |
App Router and Pages Router have different rendering and caching defaults |
| Existing repo needs a quick read-only scan |
Run bash scripts/inspect-nextjs-performance.sh <repo-root> |
Surfaces likely hotspots before deep manual review |
| User reports slow first load or high JS cost |
Check use client spread, top-level imports, images, fonts, and scripts |
Large client boundaries and heavy top-level imports are common regressions |
| User reports stale production data |
Review cache expectation, revalidation path, and route rendering mode |
Many fixes fail because freshness intent was never stated clearly |
| User reports hydration mismatch |
Check browser-only APIs, non-deterministic values, and client/server markup divergence |
Hydration bugs often appear after server-first refactors |
| You need a concrete review flow |
Use examples/performance-review-runbook.md |
Gives scenario-based steps and expected observations |
| You need a quick decision matrix |
Use references/nextjs-performance-guardrails.md |
Maps symptoms to safe checks and likely primitives |
Workflow
Confirm the target symptom and success metric.
- Examples: better LCP on
/products/[id], lower client JS on the home route, reduced CLS from font swaps, correct freshness for dashboard data.
- Do not start with blanket memoization or lazy loading.
Identify execution context.
- Determine whether the codebase uses App Router, Pages Router, or both.
- Confirm whether the environment is local, preview, or production.
- Record whether the issue is route-specific, component-specific, or global.
Capture the intended rendering and freshness model before editing.
- For App Router, decide whether the target should be static, revalidated, or fully dynamic.
- For Pages Router, confirm whether the route uses static generation, server-side rendering, or client fetching.
- Write down the expected freshness window and invalidation path.
Run the read-only inspection first.
Review architecture before micro-optimizing.
- In App Router, prefer Server Components by default.
- Add
use client only where interactivity, browser APIs, or client-only hooks are required.
- Split large client trees into a server shell plus small client islands when possible.
- Move data fetching out of client effects when framework-native server loading is available.
Check first-party optimization primitives.
- Images: prefer
next/image, correct sizing, and careful priority usage.
- Fonts: prefer
next/font; reduce unnecessary variants.
- Scripts: justify each third-party script and use the least aggressive loading strategy that works.
- Lazy loading: use for heavy optional client code, not as a substitute for bad architecture.
Only then consider React-specific render tuning.
- Investigate state placement, prop churn, broad context updates, and expensive child trees first.
- Use
memo or useMemo only when measurement or code structure shows a real payoff.
- Do not wrap nearly everything in memoization as a default response.
Validate safely.
- Prefer narrow, reversible changes.
- Rebuild and rerun the relevant local checks.
- Compare route behavior before and after.
- For production-sensitive work, define what must be verified in preview or production metrics.
Document deploy and rollback notes.
- Record what changed, why the chosen rendering/cache mode is correct, and what symptom should improve.
- If a change touches caching, note how to verify stale-content recovery and what fallback action to take if freshness becomes wrong after deploy.
Troubleshooting
Slow initial render or poor LCP
Likely causes:
- Large client component boundary near the route root
- Heavy imports in
app/layout.*, route entry files, or shared providers
- Unoptimized hero image or incorrectly prioritized assets
- Early third-party script execution
Checks:
- Search for broad
use client usage in layouts, templates, and top-level pages
- Check whether the LCP image uses
next/image with correct sizing
- Check whether fonts are loaded through
next/font
- Review third-party scripts and whether they load before interaction
Safe remediations:
- Move non-interactive UI back to server-rendered components
- Split heavy widgets behind client islands or lazy loading
- Replace plain
<img> with next/image where appropriate
- Delay or remove non-essential third-party scripts
Stale data in preview or production
Likely causes:
- Cache expectation was never made explicit
- Revalidation settings do not match freshness needs
- Route became static or dynamic unintentionally
- Operator expects deploy-time behavior to invalidate runtime caches automatically
Checks:
- Write down the required freshness window
- Review fetch caching behavior and route-level rendering assumptions
- Check whether the route should be static, revalidated, or dynamic
- Confirm how invalidation or refresh is expected to happen operationally
Safe remediations:
- Align route or fetch behavior with the intended freshness model
- Prefer the smallest change that corrects freshness without making the whole route unnecessarily dynamic
- Add handoff notes describing how to verify the fix after deploy
Hydration mismatch after refactor
Likely causes:
- Browser-only APIs used during server render
- Non-deterministic values like time, random output, or locale-sensitive formatting without coordination
- Different markup paths on server and client
Checks:
- Search for
window, document, storage APIs, or time-based rendering in shared components
- Compare server and client branches for divergent markup
- Check whether a component should be isolated behind a client boundary instead of partially executing on both sides
Safe remediations:
- Move browser-only logic into client components or effects where appropriate
- Make initial render deterministic
- Keep server markup and client hydration paths aligned
High re-render count or sluggish interaction
Likely causes:
- State lifted too high
- Broad context updates
- Expensive child tree under frequently changing props
- Memoization added without addressing prop instability
Checks:
- Identify the smallest subtree that actually depends on the changing state
- Review whether a provider wraps too much of the tree
- Look for unstable object or function props passed into expensive children
- Confirm that the expensive work is real before adding memoization
Safe remediations:
- Move state closer to where it is used
- Split expensive children from frequently updated parents
- Narrow context scope
- Add memoization only after structural fixes or measured need
Bundle regression after adding a feature
Likely causes:
- Heavy client-only dependency imported at route root or shared layout
- Entire route tree converted to
use client
- Optional widgets loaded eagerly
Checks:
- Review recent imports in layouts, route entries, and shared providers
- Identify feature code that could be deferred or isolated
- Check whether the dependency is needed during first render
Safe remediations:
- Push the dependency deeper into a smaller client island
- Lazy-load optional or below-the-fold widgets
- Keep the route shell server-rendered where possible
CLS or visual instability
Likely causes:
- Images without stable dimensions
- Font swaps or too many font variants
- Late-loading embeds or scripts changing layout
Checks:
- Confirm image sizing strategy
- Check font loading path and variant count
- Review late DOM injection from third-party code
Safe remediations:
- Provide stable image dimensions or fill containers correctly
- Use
next/font and reduce variants
- Reserve space for embeds where practical
Examples
Example 1: Review an App Router product route with poor LCP
Use examples/performance-review-runbook.md, scenario 1.
Expected pattern:
- confirm route is App Router
- inspect whether
app/products/[id]/page.* or shared layout became client-heavy
- verify hero image handling and third-party script timing
- narrow changes to the route and record measurable validation criteria
Example 2: Investigate stale dashboard data after deploy
Use examples/performance-review-runbook.md, scenario 2.
Expected pattern:
- document freshness expectation first
- inspect cache and rendering assumptions
- avoid turning the whole route dynamic unless required
- add post-deploy verification and rollback notes
Additional Resources
references/nextjs-performance-guardrails.md — compact operator matrix for routing mode, cache intent, optimization primitives, and Core Web Vitals interpretation.
- Official references to consult when needed:
- Next.js documentation
- React documentation
- Vercel Speed Insights
- Vercel Analytics
- web.dev Core Web Vitals guidance
Related Skills
Hand off when the primary task becomes:
- accessibility auditing rather than performance analysis
- test strategy or test automation design
- security review of browser code or third-party dependencies
- deployment platform configuration outside the frontend performance path
- visual design or styling with no rendering, loading, or cache concern
Provenance Note
This skill preserves the identity and intent of the upstream community skill while improving its execution quality for operators. Keep provenance explicit in review notes when using imported upstream material or adapting rule guidance into repository-specific remediation.
1---2name: react-best-practices-v2-23description: Vercel React Best Practices workflow skill. Use this skill when the user needs a practical performance optimization workflow for React and Next.js applications, especially when reviewing rendering strategy, caching behavior, bundle pressure, asset loading, or production measurement, and the operator should preserve provenance and use the packaged runbook, guardrails, and inspection script before merging or handing off.4---56# Vercel React Best Practices78## Overview910This skill curates the upstream `react-best-practices` workflow into an operator-ready execution path for React and Next.js performance work.1112Keep the original intent: improve performance without cargo-cult optimizations, preserve provenance, and stay aligned with modern React and Next.js guidance. The upgraded workflow adds sharper activation boundaries, App Router vs Pages Router decision points, measurable validation, and compact local support files that help operators inspect a repository and document safe remediation.1314Use this skill for performance-sensitive work in React or Next.js when the task involves one or more of these concerns:1516- route or component slowness17- excessive client-side JavaScript18- cache or revalidation confusion19- hydration mismatch risk20- image, font, or third-party script regressions21- code review of React or Next.js performance changes22- performance validation before deploy or handoff2324Ask one clarifying question before changing code if any of these are unclear:2526- Is this App Router or Pages Router?27- Is the problem seen locally, in preview, or in production?28- Is the target symptom slow initial load, slow navigation, stale data, hydration mismatch, or poor Core Web Vitals?2930## When to Use This Skill3132Activate this skill when the request is primarily about React or Next.js performance behavior, rendering strategy, loading behavior, or cache-aware delivery.3334### Good fit3536- Writing or refactoring Next.js pages, layouts, or route segments with performance goals37- Reviewing `use client` boundaries or deciding what should stay server-side38- Fixing slow LCP, CLS, INP, hydration mismatch, or bundle growth39- Reviewing image, font, script, or lazy-loading decisions40- Investigating stale data caused by caching or revalidation assumptions41- Preparing a performance-focused PR review, deployment review, or handoff note4243### Usually not the right skill4445- Pure styling or design-system work with no performance concern46- Accessibility audits as the main objective47- Security reviews unrelated to frontend performance behavior48- CI/CD pipeline design unrelated to frontend build or deploy verification49- Generic React bugs with no rendering, loading, or cache dimension5051If the request drifts into testing strategy, accessibility, security hardening, or deployment platform design, hand off to a more specific skill after capturing any performance findings already confirmed.5253## Operating Table5455| Situation | Start here | Why it matters |56| --- | --- | --- |57| You do not know the routing model | Inspect for `app/` vs `pages/`, then open `references/nextjs-performance-guardrails.md` | App Router and Pages Router have different rendering and caching defaults |58| Existing repo needs a quick read-only scan | Run `bash scripts/inspect-nextjs-performance.sh <repo-root>` | Surfaces likely hotspots before deep manual review |59| User reports slow first load or high JS cost | Check `use client` spread, top-level imports, images, fonts, and scripts | Large client boundaries and heavy top-level imports are common regressions |60| User reports stale production data | Review cache expectation, revalidation path, and route rendering mode | Many fixes fail because freshness intent was never stated clearly |61| User reports hydration mismatch | Check browser-only APIs, non-deterministic values, and client/server markup divergence | Hydration bugs often appear after server-first refactors |62| You need a concrete review flow | Use `examples/performance-review-runbook.md` | Gives scenario-based steps and expected observations |63| You need a quick decision matrix | Use `references/nextjs-performance-guardrails.md` | Maps symptoms to safe checks and likely primitives |6465## Workflow66671. **Confirm the target symptom and success metric.**68 - Examples: better LCP on `/products/[id]`, lower client JS on the home route, reduced CLS from font swaps, correct freshness for dashboard data.69 - Do not start with blanket memoization or lazy loading.70712. **Identify execution context.**72 - Determine whether the codebase uses App Router, Pages Router, or both.73 - Confirm whether the environment is local, preview, or production.74 - Record whether the issue is route-specific, component-specific, or global.75763. **Capture the intended rendering and freshness model before editing.**77 - For App Router, decide whether the target should be static, revalidated, or fully dynamic.78 - For Pages Router, confirm whether the route uses static generation, server-side rendering, or client fetching.79 - Write down the expected freshness window and invalidation path.80814. **Run the read-only inspection first.**82 - Use:83 ```bash84 bash scripts/inspect-nextjs-performance.sh .85 ```86 - Treat the output as triage, not proof. Confirm each finding manually in code.87885. **Review architecture before micro-optimizing.**89 - In App Router, prefer Server Components by default.90 - Add `use client` only where interactivity, browser APIs, or client-only hooks are required.91 - Split large client trees into a server shell plus small client islands when possible.92 - Move data fetching out of client effects when framework-native server loading is available.93946. **Check first-party optimization primitives.**95 - Images: prefer `next/image`, correct sizing, and careful priority usage.96 - Fonts: prefer `next/font`; reduce unnecessary variants.97 - Scripts: justify each third-party script and use the least aggressive loading strategy that works.98 - Lazy loading: use for heavy optional client code, not as a substitute for bad architecture.991007. **Only then consider React-specific render tuning.**101 - Investigate state placement, prop churn, broad context updates, and expensive child trees first.102 - Use `memo` or `useMemo` only when measurement or code structure shows a real payoff.103 - Do not wrap nearly everything in memoization as a default response.1041058. **Validate safely.**106 - Prefer narrow, reversible changes.107 - Rebuild and rerun the relevant local checks.108 - Compare route behavior before and after.109 - For production-sensitive work, define what must be verified in preview or production metrics.1101119. **Document deploy and rollback notes.**112 - Record what changed, why the chosen rendering/cache mode is correct, and what symptom should improve.113 - If a change touches caching, note how to verify stale-content recovery and what fallback action to take if freshness becomes wrong after deploy.114115## Troubleshooting116117### Slow initial render or poor LCP118119Likely causes:120- Large client component boundary near the route root121- Heavy imports in `app/layout.*`, route entry files, or shared providers122- Unoptimized hero image or incorrectly prioritized assets123- Early third-party script execution124125Checks:126- Search for broad `use client` usage in layouts, templates, and top-level pages127- Check whether the LCP image uses `next/image` with correct sizing128- Check whether fonts are loaded through `next/font`129- Review third-party scripts and whether they load before interaction130131Safe remediations:132- Move non-interactive UI back to server-rendered components133- Split heavy widgets behind client islands or lazy loading134- Replace plain `<img>` with `next/image` where appropriate135- Delay or remove non-essential third-party scripts136137### Stale data in preview or production138139Likely causes:140- Cache expectation was never made explicit141- Revalidation settings do not match freshness needs142- Route became static or dynamic unintentionally143- Operator expects deploy-time behavior to invalidate runtime caches automatically144145Checks:146- Write down the required freshness window147- Review fetch caching behavior and route-level rendering assumptions148- Check whether the route should be static, revalidated, or dynamic149- Confirm how invalidation or refresh is expected to happen operationally150151Safe remediations:152- Align route or fetch behavior with the intended freshness model153- Prefer the smallest change that corrects freshness without making the whole route unnecessarily dynamic154- Add handoff notes describing how to verify the fix after deploy155156### Hydration mismatch after refactor157158Likely causes:159- Browser-only APIs used during server render160- Non-deterministic values like time, random output, or locale-sensitive formatting without coordination161- Different markup paths on server and client162163Checks:164- Search for `window`, `document`, storage APIs, or time-based rendering in shared components165- Compare server and client branches for divergent markup166- Check whether a component should be isolated behind a client boundary instead of partially executing on both sides167168Safe remediations:169- Move browser-only logic into client components or effects where appropriate170- Make initial render deterministic171- Keep server markup and client hydration paths aligned172173### High re-render count or sluggish interaction174175Likely causes:176- State lifted too high177- Broad context updates178- Expensive child tree under frequently changing props179- Memoization added without addressing prop instability180181Checks:182- Identify the smallest subtree that actually depends on the changing state183- Review whether a provider wraps too much of the tree184- Look for unstable object or function props passed into expensive children185- Confirm that the expensive work is real before adding memoization186187Safe remediations:188- Move state closer to where it is used189- Split expensive children from frequently updated parents190- Narrow context scope191- Add memoization only after structural fixes or measured need192193### Bundle regression after adding a feature194195Likely causes:196- Heavy client-only dependency imported at route root or shared layout197- Entire route tree converted to `use client`198- Optional widgets loaded eagerly199200Checks:201- Review recent imports in layouts, route entries, and shared providers202- Identify feature code that could be deferred or isolated203- Check whether the dependency is needed during first render204205Safe remediations:206- Push the dependency deeper into a smaller client island207- Lazy-load optional or below-the-fold widgets208- Keep the route shell server-rendered where possible209210### CLS or visual instability211212Likely causes:213- Images without stable dimensions214- Font swaps or too many font variants215- Late-loading embeds or scripts changing layout216217Checks:218- Confirm image sizing strategy219- Check font loading path and variant count220- Review late DOM injection from third-party code221222Safe remediations:223- Provide stable image dimensions or fill containers correctly224- Use `next/font` and reduce variants225- Reserve space for embeds where practical226227## Examples228229### Example 1: Review an App Router product route with poor LCP230231Use `examples/performance-review-runbook.md`, scenario 1.232233Expected pattern:234- confirm route is App Router235- inspect whether `app/products/[id]/page.*` or shared layout became client-heavy236- verify hero image handling and third-party script timing237- narrow changes to the route and record measurable validation criteria238239### Example 2: Investigate stale dashboard data after deploy240241Use `examples/performance-review-runbook.md`, scenario 2.242243Expected pattern:244- document freshness expectation first245- inspect cache and rendering assumptions246- avoid turning the whole route dynamic unless required247- add post-deploy verification and rollback notes248249## Additional Resources250251- `references/nextjs-performance-guardrails.md` — compact operator matrix for routing mode, cache intent, optimization primitives, and Core Web Vitals interpretation.252- Official references to consult when needed:253 - Next.js documentation254 - React documentation255 - Vercel Speed Insights256 - Vercel Analytics257 - web.dev Core Web Vitals guidance258259## Related Skills260261Hand off when the primary task becomes:262- accessibility auditing rather than performance analysis263- test strategy or test automation design264- security review of browser code or third-party dependencies265- deployment platform configuration outside the frontend performance path266- visual design or styling with no rendering, loading, or cache concern267268## Provenance Note269270This skill preserves the identity and intent of the upstream community skill while improving its execution quality for operators. Keep provenance explicit in review notes when using imported upstream material or adapting rule guidance into repository-specific remediation.