| name | Performance Fundamentals |
| description | Auto-invoke when reviewing loops, data fetching, rendering, database queries, or resource-intensive operations. Identifies N+1 queries, unnecessary re-renders, memory leaks, and scalability issues. |
Performance Fundamentals Review
"Premature optimization is the root of all evil, but mature ignorance is worse."
When to Apply
Activate this skill when reviewing:
- Database queries (especially in loops)
- React/Vue render logic
- API response payloads
- Data transformations
- File operations
- Caching decisions
Review Checklist
Database Performance
Frontend Performance
API Performance
Memory & Resources
Common Mistakes (Anti-Patterns)
1. The N+1 Query Problem
❌ const users = await User.findAll();
for (const user of users) {
user.posts = await Post.findByUserId(user.id); // N queries!
}
✅ const users = await User.findAll({
include: [{ model: Post }] // 1 query with JOIN
});
2. Unnecessary Re-renders
❌ function Parent() {
const handleClick = () => {}; // New function every render
return <Child onClick={handleClick} />;
}
✅ function Parent() {
const handleClick = useCallback(() => {}, []);
return <Child onClick={handleClick} />;
}
3. Computing in Render
❌ function UserList({ users }) {
// Runs on every render
const sorted = users.sort((a, b) => a.name.localeCompare(b.name));
return <ul>{sorted.map(...)}</ul>;
}
✅ function UserList({ users }) {
const sorted = useMemo(
() => [...users].sort((a, b) => a.name.localeCompare(b.name)),
[users]
);
return <ul>{sorted.map(...)}</ul>;
}
4. Fetching Everything
❌ GET /api/users → returns 10,000 users with all fields
✅ GET /api/users?page=1&limit=20&fields=id,name,email
5. Missing Cleanup
❌ useEffect(() => {
const interval = setInterval(fetchData, 5000);
// No cleanup! Runs forever.
}, []);
✅ useEffect(() => {
const interval = setInterval(fetchData, 5000);
return () => clearInterval(interval);
}, []);
Socratic Questions
Ask the junior these questions instead of giving answers:
- Scale: "What happens when there are 10,000 items? 1,000,000?"
- Queries: "How many database queries does this operation make?"
- Re-renders: "When this state changes, what components re-render?"
- Memory: "Is anything holding a reference after it's no longer needed?"
- Payload: "Does the client need ALL of this data?"
Big O Quick Reference
| Pattern |
Complexity |
Example |
At 10,000 items |
| Direct lookup |
O(1) |
map.get(key) |
1 op |
| Single loop |
O(n) |
array.find() |
10,000 ops |
| Nested loops |
O(n²) |
for i { for j } |
100,000,000 ops |
| Sort |
O(n log n) |
array.sort() |
~130,000 ops |
Performance Targets
| Metric |
Target |
Measure With |
| Time to First Byte (TTFB) |
< 600ms |
DevTools Network |
| Largest Contentful Paint (LCP) |
< 2.5s |
Lighthouse |
| First Input Delay (FID) |
< 100ms |
Lighthouse |
| Cumulative Layout Shift (CLS) |
< 0.1 |
Lighthouse |
| API Response Time |
< 200ms (p95) |
Server metrics |
Red Flags to Call Out
| Flag |
Question to Ask |
| Query inside a loop |
"Can we batch this into one query?" |
| No pagination |
"What if there are 100,000 records?" |
SELECT * |
"Do we need all these fields?" |
| Large JSON in localStorage |
"Will this slow down page load?" |
| Inline function in JSX |
"Does this create a new function every render?" |
| setInterval without cleanup |
"What clears this when the component unmounts?" |
| Synchronous file operations |
"Should this be async?" |
| No loading states |
"What does the user see while waiting?" |
Quick Wins
- Add indexes to frequently queried DB columns
- Paginate all list endpoints
- Lazy load below-the-fold content
- Compress API responses
- Cache expensive computations with useMemo
- Debounce search inputs
- Virtualize long lists (react-window)