بنقرة واحدة
next-best-practices
React and Next.js performance optimization patterns from Vercel Engineering
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
React and Next.js performance optimization patterns from Vercel Engineering
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Creative direction for AI image generation — distill a codebase's FEEL canon (taste tokens, TDRs, persona files) into prompt-ready material vocabulary, map product architecture to scene systems, and enforce visual discipline across banner sets and scene stacks.
Analyze feedback logs to detect design preference patterns. Auto-contributes HIGH confidence patterns upstream.
Motion design and animation patterns for UI based on Emil Kowalski's principles
Touch, keyboard, and form interaction patterns for accessible UI
Design physics system for UI interactions - sync strategies, timing, confirmations
Convert vague "feel" feedback into specific actionable fixes via decomposition questions
| name | next-best-practices |
| description | React and Next.js performance optimization patterns from Vercel Engineering |
| user-invocable | true |
| allowed-tools | Read, Write, Glob, Grep, Edit |
Comprehensive performance optimization guide for React and Next.js applications, based on Vercel Engineering guidelines. Contains 57 rules across 8 categories, prioritized by impact.
/next
Reference these guidelines when:
| Priority | Category | Impact | Rules |
|---|---|---|---|
| 1 | Eliminating Waterfalls | CRITICAL | 5 |
| 2 | Bundle Size Optimization | CRITICAL | 5 |
| 3 | Server-Side Performance | HIGH | 7 |
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | 4 |
| 5 | Re-render Optimization | MEDIUM | 12 |
| 6 | Rendering Performance | MEDIUM | 9 |
| 7 | JavaScript Performance | LOW-MEDIUM | 12 |
| 8 | Advanced Patterns | LOW | 3 |
Start with CRITICAL categories first:
Sequential async operations are the #1 cause of slow pages.
Use Promise.all() for independent operations:
// Bad - sequential, slow
const user = await getUser(id);
const posts = await getPosts(id);
const comments = await getComments(id);
// Good - parallel, fast
const [user, posts, comments] = await Promise.all([
getUser(id),
getPosts(id),
getComments(id),
]);
Move await into branches where actually used:
// Bad - always waits even if not needed
async function getData(shouldFetch: boolean) {
const data = await fetchData();
if (shouldFetch) {
return data;
}
return null;
}
// Good - only awaits when needed
async function getData(shouldFetch: boolean) {
if (shouldFetch) {
return await fetchData();
}
return null;
}
Use Suspense to stream content:
// Good - streams independently
<Suspense fallback={<HeaderSkeleton />}>
<Header />
</Suspense>
<Suspense fallback={<ContentSkeleton />}>
<Content />
</Suspense>
Import directly, avoid barrel files:
// Bad - imports entire barrel, tree-shaking fails
import { Button } from "@/components";
// Good - imports only what's needed
import { Button } from "@/components/button";
Use next/dynamic for heavy components:
// Bad - loaded on initial page load
import HeavyChart from "@/components/heavy-chart";
// Good - loaded only when needed
const HeavyChart = dynamic(() => import("@/components/heavy-chart"), {
loading: () => <ChartSkeleton />,
});
Load analytics/logging after hydration:
// Good - defer non-critical scripts
useEffect(() => {
// Load analytics after hydration
import("@/lib/analytics").then((mod) => mod.init());
}, []);
Load modules only when feature is activated:
// Good - load on demand
const handleExport = async () => {
const { exportToPDF } = await import("@/lib/pdf-export");
exportToPDF(data);
};
Use React.cache() for per-request deduplication:
// Good - deduplicated within same request
import { cache } from "react";
export const getUser = cache(async (id: string) => {
return await db.user.findUnique({ where: { id } });
});
Restructure components to parallelize fetches:
// Bad - sequential in parent
async function Page() {
const user = await getUser();
const posts = await getPosts(user.id); // Waits for user
return <Content user={user} posts={posts} />;
}
// Good - parallel with Suspense
async function Page() {
const user = await getUser();
return (
<>
<UserInfo user={user} />
<Suspense fallback={<PostsSkeleton />}>
<Posts userId={user.id} />
</Suspense>
</>
);
}
Minimize data passed to client components:
// Bad - passes entire object
<ClientComponent data={fullUserObject} />
// Good - passes only what's needed
<ClientComponent name={user.name} avatar={user.avatar} />
Use SWR for automatic request deduplication:
// Good - SWR handles deduplication
import useSWR from "swr";
function UserProfile({ userId }) {
const { data: user } = useSWR(`/api/users/${userId}`, fetcher);
return <div>{user?.name}</div>;
}
Use passive listeners for scroll:
// Good - passive for better scroll performance
window.addEventListener("scroll", handleScroll, { passive: true });
Extract expensive work into memoized components:
// Bad - recalculates on every parent render
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>{count}</button>
<ExpensiveList items={items} /> {/* Re-renders unnecessarily */}
</div>
);
}
// Good - memoized, only re-renders when items change
const MemoizedList = memo(ExpensiveList);
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>{count}</button>
<MemoizedList items={items} />
</div>
);
}
Pass function to useState for expensive initial values:
// Bad - runs on every render
const [data, setData] = useState(expensiveComputation());
// Good - runs only once
const [data, setData] = useState(() => expensiveComputation());
Use functional setState for stable callbacks:
// Bad - needs count in dependency array
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
// Good - stable callback, no dependencies
const increment = useCallback(() => {
setCount((c) => c + 1);
}, []);
Use startTransition for non-urgent updates:
// Good - keeps UI responsive during heavy updates
import { startTransition } from "react";
function handleSearch(query: string) {
// Urgent: update input immediately
setInputValue(query);
// Non-urgent: can be interrupted
startTransition(() => {
setSearchResults(filterResults(query));
});
}
Use content-visibility for long lists:
.list-item {
content-visibility: auto;
contain-intrinsic-size: 0 100px;
}
Use ternary, not && for conditionals:
// Bad - can render "0" or "false"
{count && <Counter count={count} />}
// Good - explicit ternary
{count > 0 ? <Counter count={count} /> : null}
Use inline script for client-only data:
// Good - prevents flash of incorrect content
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
const theme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', theme);
})();
`,
}}
/>
Use Set/Map for O(1) lookups:
// Bad - O(n) lookup
const ids = [1, 2, 3, 4, 5];
items.filter(item => ids.includes(item.id));
// Good - O(1) lookup
const idSet = new Set([1, 2, 3, 4, 5]);
items.filter(item => idSet.has(item.id));
Return early from functions:
// Bad - nested conditions
function process(data) {
if (data) {
if (data.valid) {
// ... lots of code
}
}
}
// Good - early returns
function process(data) {
if (!data) return;
if (!data.valid) return;
// ... lots of code
}
Combine multiple filter/map into one loop:
// Bad - multiple iterations
const filtered = items.filter(x => x.active);
const mapped = filtered.map(x => x.name);
// Good - single iteration
const result = items.reduce((acc, x) => {
if (x.active) acc.push(x.name);
return acc;
}, []);
CRITICAL (fix immediately):
├── Promise.all() for parallel operations
├── Import directly, not from barrels
├── next/dynamic for heavy components
├── Defer third-party scripts
└── Suspense for streaming
HIGH (fix soon):
├── React.cache() for request dedup
├── Parallel component fetching
├── Minimize client serialization
└── SWR for client fetching
MEDIUM (optimize):
├── memo() for expensive components
├── Functional setState
├── startTransition for heavy updates
├── content-visibility for lists
└── Ternary for conditional render
LOW (when time permits):
├── Set/Map for lookups
├── Early returns
├── Combine iterations
└── Cache property access
Data Fetching:
├── [ ] No sequential awaits for independent data
├── [ ] Promise.all() used where applicable
├── [ ] React.cache() for server deduplication
├── [ ] SWR for client-side fetching
└── [ ] Suspense boundaries for streaming
Bundle Size:
├── [ ] Direct imports, no barrels
├── [ ] next/dynamic for heavy components
├── [ ] Third-party scripts deferred
├── [ ] Conditional imports for features
└── [ ] Bundle analyzer checked
Rendering:
├── [ ] memo() on expensive components
├── [ ] Functional setState in callbacks
├── [ ] startTransition for heavy updates
├── [ ] content-visibility on long lists
└── [ ] Ternary for conditional rendering
Server:
├── [ ] Minimal data serialization
├── [ ] Parallel component structure
├── [ ] Server actions authenticated
└── [ ] after() for non-blocking ops