From claude-starter-kit
Optimizes frontend and backend performance via profiling, caching, database tuning, code splitting, and Core Web Vitals fixes. Use for slow page loads, failing metrics, high server costs, or poor mobile UX.
npx claudepluginhub sunnypatneedi/claude-starter-kitThis skill uses the workspace's default tool permissions.
Complete framework for identifying and fixing performance bottlenecks in web applications.
Identifies and resolves performance bottlenecks through profiling, measurement, and targeted optimization across frontend, backend, and databases.
Analyzes and optimizes app performance across frontend, backend, and database layers. Profiles Node.js/Python/web apps; reduces bundle sizes, improves queries/rendering for slowness and load times.
Optimizes performance: audits frontend Core Web Vitals with Lighthouse, profiles backends (Node/Python/Go), tunes databases (EXPLAIN ANALYZE/indexing), load tests with k6/Gatling.
Share bugs, ideas, or general feedback.
Complete framework for identifying and fixing performance bottlenecks in web applications.
Measure First:
User Perception > Actual Speed:
80/20 Rule:
Core Web Vitals:
## Performance Baseline
**LCP (Largest Contentful Paint)**
- Goal: <2.5 seconds
- Current: [X]s
- What: Time until largest content element renders
**FID (First Input Delay)**
- Goal: <100 milliseconds
- Current: [X]ms
- What: Time from first interaction to response
**CLS (Cumulative Layout Shift)**
- Goal: <0.1
- Current: [X]
- What: Unexpected layout movements
**Time to Interactive**
- Goal: <3 seconds
- Current: [X]s
**Total Page Weight**
- Goal: <1MB
- Current: [X]MB
Tools:
Image Optimization:
<!-- ❌ SLOW: Large unoptimized image -->
<img src="hero-5mb.jpg" alt="Hero" />
<!-- ✅ FAST: Responsive images with modern formats -->
<picture>
<source srcset="hero.avif" type="image/avif" />
<source srcset="hero.webp" type="image/webp" />
<img
srcset="hero-300.jpg 300w,
hero-600.jpg 600w,
hero-1200.jpg 1200w"
sizes="(max-width: 600px) 300px,
(max-width: 1200px) 600px,
1200px"
src="hero-600.jpg"
alt="Hero"
loading="lazy"
/>
</picture>
Code Splitting:
// ❌ SLOW: Load everything upfront
import { HeavyComponent } from './HeavyComponent';
import { RarelyUsedFeature } from './RarelyUsedFeature';
// ✅ FAST: Lazy load on demand
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const RarelyUsedFeature = lazy(() => import('./RarelyUsedFeature'));
// Route-based code splitting
const routes = {
'/': () => import('./pages/Home'),
'/dashboard': () => import('./pages/Dashboard'),
'/settings': () => import('./pages/Settings'),
};
JavaScript Optimization:
// ❌ SLOW: Blocking render
<script src="large-bundle.js"></script>
// ✅ FAST: Defer non-critical JS
<script src="critical.js"></script>
<script src="non-critical.js" defer></script>
// Debounce expensive operations
function debounce(fn, delay) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
const handleSearch = debounce(async (query) => {
const results = await searchAPI(query);
displayResults(results);
}, 300);
// Use web workers for heavy computation
const worker = new Worker('heavy-task.js');
worker.postMessage(largeDataset);
worker.onmessage = (e) => handleResults(e.data);
CSS Optimization:
/* ❌ SLOW: Expensive selectors */
.container div span a { }
/* ✅ FAST: Specific selectors */
.nav-link { }
/* Critical CSS - inline in <head> */
.header, .hero { /* styles */ }
/* Non-critical CSS - load async */
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
Resource Hints:
<!-- Preload critical resources -->
<link rel="preload" href="/critical.css" as="style" />
<link rel="preload" href="/hero.jpg" as="image" />
<!-- Prefetch next page resources -->
<link rel="prefetch" href="/next-page.js" />
<!-- DNS prefetch for external domains -->
<link rel="dns-prefetch" href="//api.example.com" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
Database Query Optimization:
-- ❌ SLOW: No index, SELECT *
SELECT * FROM orders WHERE user_id = 123;
-- ✅ FAST: Add index
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- ✅ FAST: Select only needed columns
SELECT id, total, created_at
FROM orders
WHERE user_id = 123;
-- Use EXPLAIN ANALYZE
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 123;
-- Avoid N+1 queries
-- ❌ SLOW
const users = await User.findAll();
for (const user of users) {
user.posts = await Post.findAll({ userId: user.id }); // N queries!
}
-- ✅ FAST: Use joins or eager loading
const users = await User.findAll({
include: [Post] // 1 query with JOIN
});
Caching Strategy:
// Cache-aside pattern
async function getUser(id) {
// 1. Check cache
const cached = await redis.get(`user:${id}`);
if (cached) {
return JSON.parse(cached);
}
// 2. Cache miss: fetch from DB
const user = await db.users.findById(id);
// 3. Store in cache
await redis.setex(
`user:${id}`,
JSON.stringify(user),
3600 // TTL: 1 hour
);
return user;
}
// Cache invalidation
async function updateUser(id, data) {
await db.users.update(id, data);
await redis.del(`user:${id}`); // Invalidate
}
API Optimization:
// Response compression
const compression = require('compression');
app.use(compression());
// Pagination (not loading all data)
app.get('/api/items', async (req, res) => {
const { cursor, limit = 20 } = req.query;
const items = await db.items.findMany({
where: cursor ? { id: { gt: cursor } } : {},
take: limit + 1, // Fetch one extra to check if more
});
const hasMore = items.length > limit;
if (hasMore) items.pop();
res.json({
items,
nextCursor: hasMore ? items[items.length - 1].id : null,
});
});
// Move heavy work to background
const emailQueue = new Queue('emails');
app.post('/api/orders', async (req, res) => {
const order = await createOrder(req.body);
// Queue email instead of sending inline
await emailQueue.add({ orderId: order.id });
res.json(order); // Fast response
});
Browser DevTools:
PERFORMANCE TAB:
1. Click Record
2. Perform slow action
3. Stop recording
4. Look for:
- Long tasks (>50ms)
- Main thread blocking
- Layout thrashing
- Memory leaks
NETWORK TAB:
- Check request waterfall
- Look for slow/large requests
- Verify caching headers
- Check compression
Node.js Profiling:
# Built-in profiler
node --prof app.js
# Analyze profile
node --prof-process isolate-*.log > profile.txt
# Clinic.js for visualization
npx clinic doctor -- node app.js
npx clinic flame -- node app.js
# Memory profiling
node --inspect app.js
# Then open chrome://inspect
## Performance Budget
### Page Load
| Metric | Budget | Current | Status |
|--------|--------|---------|--------|
| LCP | <2.5s | 3.1s | ❌ |
| FID | <100ms | 85ms | ✅ |
| CLS | <0.1 | 0.05 | ✅ |
| TTI | <3s | 4.2s | ❌ |
### Assets
| Asset | Budget | Current |
|-------|--------|---------|
| Total JS | <200KB | 350KB |
| Total CSS | <50KB | 45KB |
| Images/page | <500KB | 800KB |
| Total weight | <1MB | 1.5MB |
### API
| Endpoint | P50 | P95 | P99 |
|----------|-----|-----|-----|
| GET /items | <50ms | <100ms | <200ms |
| POST /order | <100ms | <200ms | <500ms |
### Actions
1. ❌ Reduce JS bundle (200KB over budget)
2. ❌ Optimize images (300KB over budget)
3. ✅ CSS within budget
## Performance Review: [Feature]
### Frontend
- [ ] Images optimized and lazy loaded
- [ ] JavaScript code split
- [ ] Critical CSS inlined
- [ ] No layout shifts (CLS <0.1)
- [ ] Long tasks broken up (<50ms)
- [ ] Resource hints used
- [ ] Fonts optimized
### Backend
- [ ] Database queries optimized (EXPLAIN ANALYZE)
- [ ] Appropriate caching
- [ ] Heavy work moved to background
- [ ] Response compression enabled
- [ ] N+1 queries eliminated
- [ ] Connection pooling configured
### Monitoring
- [ ] Performance metrics tracked
- [ ] Alerts set for regressions
- [ ] Real user monitoring (RUM)
- [ ] Synthetic monitoring
Immediate Impact:
Enable Compression (5 min)
const compression = require('compression');
app.use(compression());
Add Image Lazy Loading (10 min)
<img src="image.jpg" loading="lazy" alt="..." />
Add Database Index (5 min)
CREATE INDEX idx_users_email ON users(email);
Cache Static Assets (10 min)
res.setHeader('Cache-Control', 'public, max-age=31536000');
Use CDN (varies)
| Problem | Impact | Fix |
|---|---|---|
| No database indexes | 100x slower queries | Add indexes on filtered columns |
| Loading all data | Memory + slow | Paginate results |
| Synchronous heavy work | Blocking | Move to background queue |
| No caching | Repeated expensive operations | Cache at multiple levels |
| Large images | Slow page load | Optimize, lazy load, responsive |
| Too much JavaScript | Slow TTI | Code split, lazy load |
| No compression | Large transfers | Enable gzip/brotli |
| N+1 queries | Database overload | Use joins or eager loading |
Measurement:
Profiling:
Monitoring:
/security-review - Security considerations for caching/database-schema - Optimizing schema design/devops-cicd - Performance testing in CI/CDLast Updated: 2026-01-22