Skills performance-reviewer
install
source · Clone the upstream repo
git clone https://github.com/TerminalSkills/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/performance-reviewer" ~/.claude/skills/terminalskills-skills-performance-reviewer && rm -rf "$T"
manifest:
skills/performance-reviewer/SKILL.mdsource content
Performance Reviewer
Overview
This skill analyzes code changes for performance regressions and optimization opportunities. It catches common issues like N+1 database queries, unnecessary re-renders in React components, missing database indexes, unoptimized loops, and bundle size increases before they reach production.
Instructions
Analyzing a Diff or PR
- Get the diff:
orgit diff main...HEADgit diff <base>...<head> - For each changed file, evaluate against these performance categories:
Database & Queries:
- Look for queries inside loops (N+1 pattern)
- Check for missing
clauses or full table scansWHERE - Identify missing indexes on columns used in
,WHERE
, orJOINORDER BY - Flag
when only specific columns are neededSELECT * - Watch for unbounded queries without
LIMIT
Frontend & Rendering:
- React: Check for missing
/useMemo
on expensive computations passed as propsuseCallback - Look for state updates that trigger unnecessary re-renders of large component trees
- Flag inline object/array creation in render (creates new reference every render)
- Check for large bundle imports (
→ suggestimport moment
)dayjs
Algorithm & Data Structures:
- Flag O(n²) or worse algorithms when O(n log n) alternatives exist
- Look for repeated array searches that should use a Set or Map
- Identify string concatenation in loops (suggest StringBuilder/join)
Memory & Resources:
- Check for missing cleanup in
(event listeners, intervals, subscriptions)useEffect - Look for growing arrays/objects that are never trimmed
- Flag missing connection pool limits or unclosed file handles
Network & I/O:
- Identify sequential API calls that could be parallelized (
)Promise.all - Check for missing pagination on list endpoints
- Flag missing caching for expensive or repeated operations
Output Format
For each issue found, report:
- File and line number
- Category (Database, Frontend, Algorithm, Memory, Network)
- Severity (Critical, Warning, Info)
- What's wrong (specific description)
- Suggested fix (concrete code suggestion)
Severity Guidelines
- Critical: Will cause visible degradation in production (N+1 in a loop, O(n²) on large datasets, memory leak)
- Warning: May cause issues at scale (missing index, unnecessary re-renders, sequential API calls)
- Info: Optimization opportunity, not urgent (bundle size suggestion, minor refactor)
Examples
Example 1: N+1 Query Detection
Input diff:
# api/views.py def list_orders(request): orders = Order.objects.filter(user=request.user) result = [] for order in orders: items = OrderItem.objects.filter(order=order) # ← query per order result.append({ "id": order.id, "total": order.total, "items": [{"name": i.product.name, "qty": i.quantity} for i in items] }) return JsonResponse(result, safe=False)
Output:
🔴 Critical — Database N+1 Query File: api/views.py:5-8 Issue: OrderItem query executes once per order, plus each i.product.name triggers another query. For 50 orders with 3 items each = 201 queries. Fix: Use select_related and prefetch_related: orders = Order.objects.filter(user=request.user).prefetch_related( Prefetch('items', queryset=OrderItem.objects.select_related('product')) ) Result: Reduces to 3 queries regardless of order count.
Example 2: React Re-render Issue
Input diff:
function UserList({ users, onSelect }) { return ( <div> {users.map(user => ( <UserCard key={user.id} user={user} style={{ padding: 16, margin: 8 }} onClick={() => onSelect(user.id)} /> ))} </div> ); }
Output:
🟡 Warning — Unnecessary Re-renders File: components/UserList.jsx:6-7 Issue: Inline object `style={{ padding: 16, margin: 8 }}` and arrow function `() => onSelect(user.id)` create new references every render, causing all UserCard components to re-render even when users haven't changed. Fix: const cardStyle = useMemo(() => ({ padding: 16, margin: 8 }), []); const handleClick = useCallback((id) => onSelect(id), [onSelect]); // Then: style={cardStyle} onClick={() => handleClick(user.id)} Impact: With 100+ users, prevents ~100 unnecessary DOM diffing operations per parent render.
Guidelines
- Focus on issues introduced by the diff, not pre-existing problems
- Prioritize Critical issues — don't bury them in a list of Info suggestions
- Always provide concrete fix suggestions, not just "optimize this"
- Consider the scale: an O(n²) loop on a 5-element array is fine; on user-generated data it's not
- When suggesting caching, specify what to cache and invalidation strategy
- Don't flag micro-optimizations that harm readability for negligible gain