Optimizing performance skill
Analyzes and optimizes application performance across frontend, backend, and database layers.
by CloudAI-X·MIT license·★ 1,416 Stars on the repo·GitHub ↗
Use now
npx degit CloudAI-X/claude-workflow-v2/skills/optimizing-performance#main ~/.claude/skills/optimizing-performanceChecked ·commit main
Files of Optimizing performance
SKILL.md
Show the full text242 lines
Optimizing Performance
When to Load
- Trigger: Diagnosing slowness, profiling, caching strategies, reducing load times, bundle size optimization
- Skip: Correctness-focused work where performance is not a concern
Performance Optimization Workflow
Copy this checklist and track progress:
Performance Optimization Progress:
- [ ] Step 1: Measure baseline performance
- [ ] Step 2: Identify bottlenecks
- [ ] Step 3: Apply targeted optimizations
- [ ] Step 4: Measure again and compare
- [ ] Step 5: Repeat if targets not met
Critical Rule: Never optimize without data. Always profile before and after changes.
Step 1: Measure Baseline
Profiling Commands
# Node.js profiling
node --prof app.js
node --prof-process isolate*.log > profile.txt
# Python profiling
python -m cProfile -o profile.stats app.py
python -m pstats profile.stats
# Web performance
lighthouse https://example.com --output=json
Step 2: Identify Bottlenecks
Common Bottleneck Categories
| Category | Symptoms | Tools |
|---|---|---|
| CPU | High CPU usage, slow computation | Profiler, flame graphs |
| Memory | High RAM, GC pauses, OOM | Heap snapshots, memory profiler |
| I/O | Slow disk/network, waiting | strace, network inspector |
| Database | Slow queries, lock contention | Query analyzer, EXPLAIN |
Step 3: Apply Optimizations
Frontend Optimizations
Bundle Size:
// ❌ Import entire library
import _ from "lodash";
// ✅ Import only needed functions
import debounce from "lodash/debounce";
// ✅ Use dynamic imports for code splitting
const HeavyComponent = lazy(() => import("./HeavyComponent"));
Rendering:
// ❌ Render on every parent update
function Child({ data }) {
return <ExpensiveComponent data={data} />;
}
// ✅ Memoize when props don't change
const Child = memo(function Child({ data }) {
return <ExpensiveComponent data={data} />;
});
// ✅ Use useMemo for expensive computations
const processed = useMemo(() => expensiveCalc(data), [data]);
Images:
<!-- ❌ Unoptimized -->
<img src="large-image.jpg" />
<!-- ✅ Optimized -->
<img
src="image.webp"
srcset="image-300.webp 300w, image-600.webp 600w"
sizes="(max-width: 600px) 300px, 600px"
width="600"
height="400"
alt="Description"
loading="lazy"
decoding="async"
/>
Backend Optimizations
Database Queries:
-- ❌ N+1 Query Problem
SELECT * FROM users;
-- Then for each user:
SELECT * FROM orders WHERE user_id = ?;
-- ✅ Single query with JOIN
SELECT u.id, u.name, o.id AS order_id, o.total
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- ✅ Or use pagination
SELECT id, name FROM users WHERE id > :last_id ORDER BY id LIMIT 100;
Caching Strategy:
// Multi-layer caching
const getUser = async (id) => {
// L1: In-memory cache (fastest)
let user = memoryCache.get(`user:${id}`);
if (user) return user;
// L2: Redis cache (fast)
user = await redis.get(`user:${id}`);
if (user) {
user = JSON.parse(user);
memoryCache.set(`user:${id}`, user, 60);
return user;
}
// L3: Database (slow)
user = await db.users.findById(id);
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
memoryCache.set(`user:${id}`, user, 60);
return user;
};
Async Processing:
// ❌ Blocking operation
app.post("/upload", async (req, res) => {
await processVideo(req.file); // Takes 5 minutes
res.send("Done");
});
// ✅ Queue for background processing
app.post("/upload", async (req, res) => {
const jobId = await queue.add("processVideo", { file: req.file });
res.status(202).send({ jobId, status: "processing" });
});
Algorithm Optimizations
// ❌ O(n²) - nested loops
function findDuplicates(arr) {
const duplicates = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) duplicates.push(arr[i]);
}
}
return duplicates;
}
// ✅ O(n) - hash map
function findDuplicates(arr) {
const seen = new Set();
const duplicates = new Set();
for (const item of arr) {
if (seen.has(item)) duplicates.add(item);
seen.add(item);
}
return [...duplicates];
}
Step 4: Measure Again
After applying optimizations, re-run profiling and compare:
Comparison Checklist:
- [ ] Run same profiling tools as baseline
- [ ] Compare metrics before vs after
- [ ] Verify no regressions in other areas
- [ ] Document improvement percentages
Performance Targets
Web Vitals
| Metric | Good | Needs Work | Poor |
|---|---|---|---|
| LCP | < 2.5s | 2.5-4s | > 4s |
| INP | < 200ms | 200-500ms | > 500ms |
| CLS | < 0.1 | 0.1-0.25 | > 0.25 |
| TTFB | < 800ms | 800ms-1.8s | > 1.8s |
API Performance
| Metric | Target |
|---|---|
| P50 Latency | < 100ms |
| P95 Latency | < 500ms |
| P99 Latency | < 1s |
| Error Rate | < 0.1% |
Validation
After optimization, validate results:
Performance Validation:
- [ ] Metrics improved from baseline
- [ ] No functionality regressions
- [ ] No new errors introduced
- [ ] Changes are sustainable (not one-time fixes)
- [ ] Performance gains documented
If targets not met, return to Step 2 and identify remaining bottlenecks.
| 1 | |
| 2 | name optimizing-performance |
| 3 | description Analyzes and optimizes application performance across frontend, backend, and database layers. Use when diagnosing slowness, improving load times, optimizing queries, reducing bundle size, or when asked about performance issues. |
| 4 | |
| 5 | |
| 6 | # Optimizing Performance |
| 7 | |
| 8 | ### When to Load |
| 9 | |
| 10 | **Trigger**: Diagnosing slowness, profiling, caching strategies, reducing load times, bundle size optimization |
| 11 | **Skip**: Correctness-focused work where performance is not a concern |
| 12 | |
| 13 | ## Performance Optimization Workflow |
| 14 | |
| 15 | Copy this checklist and track progress: |
| 16 | |
| 17 | |
| 18 | Performance Optimization Progress: |
| 19 | - [ ] Step 1: Measure baseline performance |
| 20 | - [ ] Step 2: Identify bottlenecks |
| 21 | - [ ] Step 3: Apply targeted optimizations |
| 22 | - [ ] Step 4: Measure again and compare |
| 23 | - [ ] Step 5: Repeat if targets not met |
| 24 | |
| 25 | |
| 26 | **Critical Rule**: Never optimize without data. Always profile before and after changes. |
| 27 | |
| 28 | ## Step 1: Measure Baseline |
| 29 | |
| 30 | ### Profiling Commands |
| 31 | |
| 32 | |
| 33 | # Node.js profiling |
| 34 | node --prof app.js |
| 35 | node --prof-process isolate*.log > profile.txt |
| 36 | |
| 37 | # Python profiling |
| 38 | python -m cProfile -o profile.stats app.py |
| 39 | python -m pstats profile.stats |
| 40 | |
| 41 | # Web performance |
| 42 | lighthouse https://example.com --output=json |
| 43 | |
| 44 | |
| 45 | ## Step 2: Identify Bottlenecks |
| 46 | |
| 47 | ### Common Bottleneck Categories |
| 48 | |
| 49 | | Category | Symptoms | Tools | |
| 50 | | -------- | -------------------------------- | ------------------------------- | |
| 51 | | CPU | High CPU usage, slow computation | Profiler, flame graphs | |
| 52 | | Memory | High RAM, GC pauses, OOM | Heap snapshots, memory profiler | |
| 53 | | I/O | Slow disk/network, waiting | strace, network inspector | |
| 54 | | Database | Slow queries, lock contention | Query analyzer, EXPLAIN | |
| 55 | |
| 56 | ## Step 3: Apply Optimizations |
| 57 | |
| 58 | ### Frontend Optimizations |
| 59 | |
| 60 | **Bundle Size:** |
| 61 | |
| 62 | |
| 63 | // ❌ Import entire library |
| 64 | import _ from "lodash"; |
| 65 | |
| 66 | // ✅ Import only needed functions |
| 67 | import debounce from "lodash/debounce"; |
| 68 | |
| 69 | // ✅ Use dynamic imports for code splitting |
| 70 | const HeavyComponent = lazy(() => import("./HeavyComponent")); |
| 71 | |
| 72 | |
| 73 | **Rendering:** |
| 74 | |
| 75 | |
| 76 | // ❌ Render on every parent update |
| 77 | function Child({ data }) { |
| 78 | return <ExpensiveComponent data={data} />; |
| 79 | } |
| 80 | |
| 81 | // ✅ Memoize when props don't change |
| 82 | const Child = memo(function Child({ data }) { |
| 83 | return <ExpensiveComponent data={data} />; |
| 84 | }); |
| 85 | |
| 86 | // ✅ Use useMemo for expensive computations |
| 87 | const processed = useMemo(() => expensiveCalc(data), [data]); |
| 88 | |
| 89 | |
| 90 | **Images:** |
| 91 | |
| 92 | |
| 93 | <!-- ❌ Unoptimized --> |
| 94 | <img src="large-image.jpg" /> |
| 95 | |
| 96 | <!-- ✅ Optimized --> |
| 97 | <img |
| 98 | src="image.webp" |
| 99 | srcset="image-300.webp 300w, image-600.webp 600w" |
| 100 | sizes="(max-width: 600px) 300px, 600px" |
| 101 | width="600" |
| 102 | height="400" |
| 103 | alt="Description" |
| 104 | loading="lazy" |
| 105 | decoding="async" |
| 106 | /> |
| 107 | |
| 108 | |
| 109 | ### Backend Optimizations |
| 110 | |
| 111 | **Database Queries:** |
| 112 | |
| 113 | |
| 114 | -- ❌ N+1 Query Problem |
| 115 | SELECT * FROM users; |
| 116 | -- Then for each user: |
| 117 | SELECT * FROM orders WHERE user_id = ?; |
| 118 | |
| 119 | -- ✅ Single query with JOIN |
| 120 | SELECT u.id, u.name, o.id AS order_id, o.total |
| 121 | FROM users u |
| 122 | LEFT JOIN orders o ON u.id = o.user_id; |
| 123 | |
| 124 | -- ✅ Or use pagination |
| 125 | SELECT id, name FROM users WHERE id > :last_id ORDER BY id LIMIT 100; |
| 126 | |
| 127 | |
| 128 | **Caching Strategy:** |
| 129 | |
| 130 | |
| 131 | // Multi-layer caching |
| 132 | const getUser = async (id) => { |
| 133 | // L1: In-memory cache (fastest) |
| 134 | let user = memoryCache.get(`user:${id}`); |
| 135 | if (user) return user; |
| 136 | |
| 137 | // L2: Redis cache (fast) |
| 138 | user = await redis.get(`user:${id}`); |
| 139 | if (user) { |
| 140 | user = JSON.parse(user); |
| 141 | memoryCache.set(`user:${id}`, user, 60); |
| 142 | return user; |
| 143 | } |
| 144 | |
| 145 | // L3: Database (slow) |
| 146 | user = await db.users.findById(id); |
| 147 | await redis.setex(`user:${id}`, 3600, JSON.stringify(user)); |
| 148 | memoryCache.set(`user:${id}`, user, 60); |
| 149 | |
| 150 | return user; |
| 151 | }; |
| 152 | |
| 153 | |
| 154 | **Async Processing:** |
| 155 | |
| 156 | |
| 157 | // ❌ Blocking operation |
| 158 | app.post("/upload", async (req, res) => { |
| 159 | await processVideo(req.file); // Takes 5 minutes |
| 160 | res.send("Done"); |
| 161 | }); |
| 162 | |
| 163 | // ✅ Queue for background processing |
| 164 | app.post("/upload", async (req, res) => { |
| 165 | const jobId = await queue.add("processVideo", { file: req.file }); |
| 166 | res.status(202).send({ jobId, status: "processing" }); |
| 167 | }); |
| 168 | |
| 169 | |
| 170 | ### Algorithm Optimizations |
| 171 | |
| 172 | |
| 173 | // ❌ O(n²) - nested loops |
| 174 | function findDuplicates(arr) { |
| 175 | const duplicates = []; |
| 176 | for (let i = 0; i < arr.length; i++) { |
| 177 | for (let j = i + 1; j < arr.length; j++) { |
| 178 | if (arr[i] === arr[j]) duplicates.push(arr[i]); |
| 179 | } |
| 180 | } |
| 181 | return duplicates; |
| 182 | } |
| 183 | |
| 184 | // ✅ O(n) - hash map |
| 185 | function findDuplicates(arr) { |
| 186 | const seen = new Set(); |
| 187 | const duplicates = new Set(); |
| 188 | for (const item of arr) { |
| 189 | if (seen.has(item)) duplicates.add(item); |
| 190 | seen.add(item); |
| 191 | } |
| 192 | return [...duplicates]; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | ## Step 4: Measure Again |
| 197 | |
| 198 | After applying optimizations, re-run profiling and compare: |
| 199 | |
| 200 | |
| 201 | Comparison Checklist: |
| 202 | - [ ] Run same profiling tools as baseline |
| 203 | - [ ] Compare metrics before vs after |
| 204 | - [ ] Verify no regressions in other areas |
| 205 | - [ ] Document improvement percentages |
| 206 | |
| 207 | |
| 208 | ## Performance Targets |
| 209 | |
| 210 | ### Web Vitals |
| 211 | |
| 212 | | Metric | Good | Needs Work | Poor | |
| 213 | | ------ | ------- | ---------- | ------- | |
| 214 | | LCP | < 2.5s | 2.5-4s | > 4s | |
| 215 | | INP | < 200ms | 200-500ms | > 500ms | |
| 216 | | CLS | < 0.1 | 0.1-0.25 | > 0.25 | |
| 217 | | TTFB | < 800ms | 800ms-1.8s | > 1.8s | |
| 218 | |
| 219 | ### API Performance |
| 220 | |
| 221 | | Metric | Target | |
| 222 | | ----------- | ------- | |
| 223 | | P50 Latency | < 100ms | |
| 224 | | P95 Latency | < 500ms | |
| 225 | | P99 Latency | < 1s | |
| 226 | | Error Rate | < 0.1% | |
| 227 | |
| 228 | ## Validation |
| 229 | |
| 230 | After optimization, validate results: |
| 231 | |
| 232 | |
| 233 | Performance Validation: |
| 234 | - [ ] Metrics improved from baseline |
| 235 | - [ ] No functionality regressions |
| 236 | - [ ] No new errors introduced |
| 237 | - [ ] Changes are sustainable (not one-time fixes) |
| 238 | - [ ] Performance gains documented |
| 239 | |
| 240 | |
| 241 | If targets not met, return to Step 2 and identify remaining bottlenecks. |
| 242 |
Discussion
Alternatives
Browse more free Claude skills or everything in Development.