#What it does
The /perf skill hunts down performance bottlenecks in your code through static analysis and pattern recognition. It identifies N+1 queries, unnecessary re-renders, unbounded loops, missing indexes, oversized bundles, and expensive computations that run on every request. Every finding comes with a concrete fix and an estimated impact.
#How to use
bash
/perfbash
/perf src/api/orders.tsbash
/perf --focus frontend#What it checks
#Backend
- N+1 Queries -- Database calls inside loops, missing joins, unbatched fetches
- Missing Pagination -- List endpoints that return unbounded result sets
- Blocking Operations -- Synchronous file I/O, CPU-heavy work on the main thread
- Cache Opportunities -- Repeated expensive computations with stable inputs
- Connection Management -- Missing connection pooling, leaked database connections
#Frontend
- Bundle Size -- Large dependencies that could be lazy-loaded or replaced with lighter alternatives
- Unnecessary Re-renders -- Components re-rendering due to unstable references, missing memoization, or prop drilling
- Image Optimization -- Unoptimized images, missing
width/heightattributes, wrong format - Layout Shifts -- Elements without explicit dimensions that cause CLS
- Hydration Cost -- Server components that should not be client components and vice versa
#API
- Response Size -- Endpoints returning more data than the client needs
- Missing Compression -- Responses not using gzip or brotli
- Slow Serialization -- Expensive object transformations on every request
#Example
bash
> /perf src/api/orders.ts
## Performance Analysis: 3 issues found
### [HIGH] N+1 Query on line 28
getOrders() fetches orders, then loops to fetch customer
for each one. With 100 orders, this makes 101 queries.
Fix: JOIN customers in the original query.
Impact: ~95% reduction in query count for list endpoint.
### [MEDIUM] Missing pagination on line 15
GET /api/orders returns all orders. With 10K orders,
response is ~4MB and takes 3.2s to serialize.
Fix: Add limit/offset with default page size of 25.
Impact: Response drops from ~4MB to ~100KB.
### [LOW] Repeated date formatting on line 45
formatDate() is called per-row with the same locale config.
Fix: Create formatter once outside the loop.
Impact: Marginal (~5ms on large datasets).