| name | quality-perf-review |
| description | Analyze a codebase for performance bottlenecks in full-stack web applications. Use when user says "quality-perf-review", "perf review", "performance review", "find bottlenecks", "optimize performance", "slow code", "performance audit", or "why is my app slow". Interactive workflow that discusses each finding before moving on. |
Performance Review Skill
Analyze a full-stack web application for real performance bottlenecks. Focus on evidence-based issues, not generic suggestions. Interactive workflow that discusses each finding with the user.
When to Use This Skill
Use this skill when the user requests:
- "Perf review" / "Performance review"
- "Find bottlenecks"
- "Optimize performance"
- "Why is my app slow?"
- "Performance audit"
- "Slow code analysis"
Core Principles
- Evidence over intuition: Only flag issues you can prove are bottlenecks
- Impact over quantity: Fewer high-impact findings beat many micro-optimizations
- Safety first: Every suggestion must not change functionality
- Interactive review: Discuss each finding before moving to the next
Workflow
Phase 1: Project Discovery
Before analyzing, understand the project:
ls package.json bun.lockb yarn.lock pnpm-lock.yaml 2>/dev/null
find . -name "*.bench.ts" -o -name "*.benchmark.ts" -o -name "bench.ts" 2>/dev/null
ls .clinic clinic.json 0x.json 2>/dev/null
grep -l "react\|vue\|svelte\|next\|nuxt" package.json 2>/dev/null
Inform the user:
- "I'll analyze [project type] for performance issues."
- "Found existing benchmarks: [list] / No existing benchmarks found."
- "I'll focus on [backend/frontend/both] based on your project structure."
Phase 2: Static Analysis
Analyze code for known performance anti-patterns. Check each category based on what's relevant to the project.
Backend Performance Checks
1. Database Queries (N+1, Missing Indexes)
Look for:
- Queries inside loops (N+1 pattern)
- Missing
include/join in ORM queries
SELECT * when only specific columns needed
- Missing pagination on large result sets
Grep patterns:
- "\.find\(" inside forEach/map/for loops
- "await.*query" inside loops
- "SELECT \*" in raw queries
2. API Endpoints
Look for:
- Synchronous operations that should be async
- Missing response streaming for large payloads
- Unnecessary serialization/deserialization
- Missing caching headers
3. Memory Patterns
Look for:
- Growing arrays/objects without bounds
- Event listeners not being removed
- Large objects held in closures
- Missing cleanup in long-running processes
4. I/O Operations
Look for:
readFileSync / writeFileSync (sync file ops)
- Unbuffered streams
- Missing compression for responses
- Sequential I/O that could be parallel
5. Event Loop Blocking
Look for:
- CPU-intensive operations in request handlers
- Large JSON.parse/JSON.stringify on main thread
- Synchronous crypto operations
- Missing worker threads for heavy computation
Frontend Performance Checks
1. Bundle Size
Look for:
- Large dependencies (moment.js, lodash full import)
- Missing tree-shaking (
import lodash vs import { map } from 'lodash')
- Duplicate dependencies
- Dev dependencies in production bundle
bun build --analyze 2>/dev/null || npx webpack-bundle-analyzer 2>/dev/null
2. Rendering Performance
Look for:
- Components re-rendering on every parent render
- Missing
useMemo/useCallback for expensive computations
- Inline object/array creation in JSX props
- Missing
key props or using index as key
3. Asset Loading
Look for:
- Unoptimized images (missing width/height, no lazy loading)
- Render-blocking CSS/JS
- Missing preload/prefetch for critical resources
- Large fonts loading synchronously
4. Network Efficiency
Look for:
- Waterfall requests (sequential when parallel possible)
- Missing data prefetching
- Over-fetching (requesting more data than needed)
- Missing response caching
Phase 3: Dynamic Analysis (Ask Permission)
If static analysis is inconclusive, offer to run benchmarks:
Question: "I'd like to run some performance measurements to identify bottlenecks more precisely. May I?"
Options:
- "Yes, run benchmarks" - Execute performance tests
- "No, continue with static analysis" - Skip dynamic analysis
- "Tell me what you'd run first" - Explain before executing
If approved, depending on project type:
For Bun/Node backend:
npx clinic doctor -- node server.js
node --prof server.js
For frontend:
bun build --minify --outdir=dist && du -sh dist/
npx webpack-bundle-analyzer stats.json
Phase 4: Interactive Review
For each finding, present it interactively:
Finding Format
## Finding [N]: [Title]
**Location:** `file/path.ts:123`
**Category:** [Database/Memory/Bundle/etc.]
**Impact:** [High/Medium/Low] - [explanation of impact]
### The Issue
[Code snippet showing the problem]
### Why This Matters
[Explanation with numbers if possible - e.g., "This query runs N times per request"]
### Proposed Fix
[Code snippet showing the fix]
### Safety Assessment
- **Regression risk:** [Low/Medium] - [explanation]
- **Behavior change:** None / [describe any edge case differences]
- **Test coverage:** [covered by X test / not covered]
- **Reversibility:** [easy to revert / requires migration]
Ask User
After presenting each finding, ask:
Question: "How would you like to proceed with this finding?"
Options:
- "Apply this fix" - I'll make the change
- "Skip for now" - Move to next finding
- "Tell me more" - Explain in more detail
- "I'll fix it myself" - Note it and move on
Phase 5: Summary
After reviewing all findings, provide a summary:
## Performance Review Summary
### Applied Fixes
1. [Finding 1] - [file:line]
2. [Finding 2] - [file:line]
### Skipped/Deferred
1. [Finding 3] - Reason: [user chose to skip / needs more investigation]
### Estimated Impact
- Database queries: X fewer per request
- Bundle size: -Y KB
- Response time: [estimated improvement]
### Recommended Next Steps
1. [Run the test suite to verify no regressions]
2. [Set up performance monitoring for X]
3. [Consider profiling Y in production]
Focus Areas
DO Focus On
- Evidence-based issues: Query counts, bundle sizes, profiler output
- High-impact patterns: O(n²) → O(n), N+1 queries, bundle bloat
- Measurable improvements: "This will reduce queries from N to 1"
- Safe optimizations: Pure performance gains with no behavior change
DO NOT Focus On
- Micro-optimizations:
for vs forEach without evidence
- Premature optimization: Caching before proving it's needed
- Speculative improvements: "This might be slow" without proof
- Behavior-changing refactors: Even if faster, flag don't fix
Safety Guarantees
Before suggesting any fix, verify:
- No behavior change: The output/result must be identical
- Test coverage: Note if the area has tests or needs them
- Reversibility: Prefer easily-revertible changes
- Edge cases: Consider null, empty, concurrent access
If uncertain about safety, present as "potential optimization" requiring user verification rather than a fix to apply.
Examples
Example: N+1 Query Detection
Bad (N+1):
const users = await db.user.findMany();
for (const user of users) {
const posts = await db.post.findMany({ where: { userId: user.id } });
}
Good (single query):
const users = await db.user.findMany({
include: { posts: true }
});
Example: Bundle Size Issue
Bad (imports entire library):
import _ from 'lodash';
const result = _.map(items, transform);
Good (tree-shakeable):
import { map } from 'lodash-es';
const result = map(items, transform);
Example: Sync File Operation
Bad (blocks event loop):
app.get('/config', (req, res) => {
const config = fs.readFileSync('./config.json');
res.json(JSON.parse(config));
});
Good (non-blocking):
app.get('/config', async (req, res) => {
const config = await Bun.file('./config.json').json();
res.json(config);
});