Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Full-stack performance analysis, optimization patterns, and monitoring strategies
.claude/skills/aiskillstore-performance-optimization/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-18 | ✓→✓ | = Same ✓ | 69% | 0% |
| case-09 | ✓→✓ | = Same ✓ | 116% | 0% |
Lighthouse (Chrome DevTools):
bash# CLI npm install -g lighthouse lighthouse https://example.com --view # Automate in CI lighthouse https://example.com --output=json --output-path=./report.json
Measure Web Vitals (React):
typescriptimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'; function sendToAnalytics(metric: any) { // Send to Google Analytics, Datadog, etc. console.log(metric); } getCLS(sendToAnalytics); getFID(sendToAnalytics); getFCP(sendToAnalytics); getLCP(sendToAnalytics); getTTFB(sendToAnalytics);
React.memo (prevent unnecessary re-renders):
tsx// ❌ Bad: child re-renders whenever the parent re-renders function ExpensiveComponent({ data }: { data: Data }) { return <div>{/* complex rendering */}</div>; } // ✅ Good: re-render only when props change const ExpensiveComponent = React.memo(({ data }: { data: Data }) => { return <div>{/* complex rendering */}</div>; });
useMemo & useCallback:
tsxfunction ProductList({ products, category }: Props) { // ✅ Memoize filtered results const filteredProducts = useMemo(() => { return products.filter(p => p.category === category); }, [products, category]); // ✅ Memoize callback const handleAddToCart = useCallback((id: string) => { addToCart(id); }, []); return ( <div> {filteredProducts.map(product => ( <ProductCard key={product.id} product={product} onAdd={handleAddToCart} /> ))} </div> ); }
Lazy Loading & Code Splitting:
tsximport { lazy, Suspense } from 'react'; // ✅ Route-based code splitting const Dashboard = lazy(() => import('./pages/Dashboard')); const Profile = lazy(() => import('./pages/Profile')); const Settings = lazy(() => import('./pages/Settings')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/profile" element={<Profile />} /> <Route path="/settings" element={<Settings />} /> </Routes> </Suspense> ); } // ✅ Component-based lazy loading const HeavyChart = lazy(() => import('./components/HeavyChart')); function Dashboard() { return ( <div> <h1>Dashboard</h1> <Suspense fallback={<Skeleton />}> <HeavyChart data={data} /> </Suspense> </div> ); }
Webpack Bundle Analyzer:
bashnpm install --save-dev webpack-bundle-analyzer # package.json { "scripts": { "analyze": "webpack-bundle-analyzer build/stats.json" } }
Tree Shaking (remove unused code):
typescript// ❌ Bad: import entire library import _ from 'lodash'; // ✅ Good: import only what you need import debounce from 'lodash/debounce';
Dynamic Imports:
typescript// ✅ Load only when needed button.addEventListener('click', async () => { const { default: Chart } = await import('chart.js'); new Chart(ctx, config); });
Next.js Image component:
tsximport Image from 'next/image'; function ProductImage() { return ( <Image src="/product.jpg" alt="Product" width={500} height={500} priority // for the LCP image placeholder="blur" // blur placeholder sizes="(max-width: 768px) 100vw, 50vw" /> ); }
Use WebP format:
html<picture> <source srcset="image.webp" type="image/webp"> <source srcset="image.jpg" type="image/jpeg"> <img src="image.jpg" alt="Fallback"> </picture>
Fix the N+1 query problem:
typescript// ❌ Bad: N+1 queries const posts = await db.post.findMany(); for (const post of posts) { const author = await db.user.findUnique({ where: { id: post.authorId } }); // 101 queries (1 + 100) } // ✅ Good: JOIN or include const posts = await db.post.findMany({ include: { author: true } }); // 1 query
Add indexes:
sql-- Identify slow queries EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com'; -- Add index CREATE INDEX idx_users_email ON users(email); -- Composite index CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
Caching (Redis):
typescriptasync function getUserProfile(userId: string) { // 1. Check cache const cached = await redis.get(`user:${userId}`); if (cached) { return JSON.parse(cached); } // 2. Query DB const user = await db.user.findUnique({ where: { id: userId } }); // 3. Store in cache (1 hour) await redis.setex(`user:${userId}`, 3600, JSON.stringify(user)); return user; }
markdown## Frontend - [ ] Prevent unnecessary re-renders with React.memo - [ ] Use useMemo/useCallback appropriately - [ ] Lazy loading & Code splitting - [ ] Optimize images (WebP, lazy loading) - [ ] Analyze and reduce bundle size ## Backend - [ ] Remove N+1 queries - [ ] Add database indexes - [ ] Redis caching - [ ] Compress API responses (gzip) - [ ] Use a CDN ## Measurement - [ ] Lighthouse score 90+ - [ ] LCP < 2.5s - [ ] FID < 100ms - [ ] CLS < 0.1
#performance #optimization #React #caching #lazy-loading #web-vitals #code-quality
<!-- Add example content here -->
<!-- Add advanced example content here -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | fail→fail | 14,419 | 12,370 | -14% | 1 | 1 | 0% | 2,525 | 4,224 | +67% | 0 | 0 | — |
case-18 | pass→pass | 16,016 | 8,839 | -45% | 1 | 1 | 0% | 2,138 | 3,608 | +69% | 0 | 0 | — |
case-19 | fail→pass | 10,931 | 12,658 | +16% | 1 | 1 | 0% | 1,941 | 3,343 | +72% | 0 | 0 | — |
case-09 | pass→pass | 13,023 | 10,977 | -16% | 1 | 1 | 0% | 1,397 | 3,012 | +116% | 0 | 0 | — |
case-10 | pass→pass | 16,429 | 13,397 | -18% | 1 | 1 | 0% | 1,907 | 3,591 | +88% | 0 | 0 | — |
case-01 | fail→fail | 49,981 | 22,398 | -55% | 1 | 1 | 0% | 7,791 | 5,564 | -29% | 0 | 0 | — |
case-02 | fail→fail | 19,214 | 20,252 | +5% | 1 | 1 | 0% | 3,005 | 4,728 | +57% | 0 | 0 | — |
case-11 | pass→pass | 14,935 | 15,018 | +1% | 1 | 1 | 0% | 1,974 | 3,754 | +90% | 0 | 0 | — |
case-03 | fail→pass | 38,999 | 25,719 | -34% | 1 | 1 | 0% | 5,883 | 6,583 | +12% | 0 | 0 | — |
case-04 | pass→pass | 14,223 | 14,373 | +1% | 1 | 1 | 0% | 2,702 | 3,796 | +40% | 0 | 0 | — |
case-05 | pass→pass | 16,724 | 18,238 | +9% | 1 | 1 | 0% | 2,285 | 4,350 | +90% | 0 | 0 | — |
case-06 | pass→pass | 15,652 | 13,814 | -12% | 1 | 1 | 0% | 2,748 | 4,351 | +58% | 0 | 0 | — |
case-07 | pass→pass | 16,103 | 10,596 | -34% | 1 | 1 | 0% | 1,994 | 3,788 | +90% | 0 | 0 | — |
case-08 | pass→pass | 13,554 | 13,801 | +2% | 1 | 1 | 0% | 2,430 | 3,558 | +46% | 0 | 0 | — |
case-13 | pass→pass | 11,405 | 5,217 | -54% | 1 | 1 | 0% | 1,108 | 2,860 | +158% | 0 | 0 | — |
case-14 | pass→pass | 6,402 | 13,120 | +105% | 1 | 1 | 0% | 1,175 | 3,451 | +194% | 0 | 0 | — |
case-15 | pass→pass | 6,303 | 11,671 | +85% | 1 | 1 | 0% | 1,016 | 3,069 | +202% | 0 | 0 | — |
case-16 | fail→pass | 19,596 | 18,111 | -8% | 1 | 1 | 0% | 2,874 | 4,527 | +58% | 0 | 0 | — |
case-17 | pass→pass | 19,722 | 18,994 | -4% | 1 | 1 | 0% | 2,336 | 4,232 | +81% | 0 | 0 | — |
case-20 | pass→pass | 14,384 | 10,659 | -26% | 1 | 1 | 0% | 1,737 | 3,893 | +124% | 0 | 0 | — |
case-21 | pass→pass | 17,760 | 45,552 | +156% | 1 | 1 | 0% | 2,434 | 4,596 | +89% | 0 | 0 | — |
case-22 | pass→pass | 9,624 | 10,582 | +10% | 1 | 1 | 0% | 797 | 3,002 | +277% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.