Performance Optimizer
Optimize application performance and scalability. Use when investigating slow applications, scaling bottlenecks, or improving response times. Covers profiling, caching, database optimization, and frontend performance.
What this skill does
# Performance Optimizer
Make applications fast, scalable, and cost-efficient.
## Core Principle
**Measure first, optimize second.** Don't guess at bottlenecks—profile, measure, then fix the slowest parts.
## Performance Budget
### Web Vitals (Target Metrics)
```yaml
Core Web Vitals:
Largest Contentful Paint (LCP): < 2.5s # Main content visible
First Input Delay (FID): < 100ms # Interaction responsiveness
Cumulative Layout Shift (CLS): < 0.1 # Visual stability
Additional Metrics:
First Contentful Paint (FCP): < 1.8s # First content rendered
Time to Interactive (TTI): < 3.8s # Fully interactive
Total Blocking Time (TBT): < 200ms # Main thread blocked
Speed Index: < 3.4s # Visual progress
Backend Metrics:
API Response Time (P95): < 500ms
Database Query Time (P95): < 100ms
Server Response Time (TTFB): < 600ms
```
---
## Phase 1: Profiling & Measurement
**Goal**: Identify actual bottlenecks, not perceived ones
### Frontend Profiling
**Chrome DevTools**:
```javascript
// 1. Performance tab → Record → Reload page
// 2. Analyze:
// - Main thread activity
// - Network waterfall
// - JavaScript execution time
// - Rendering time
// 3. Lighthouse audit
// Run: chrome://lighthouse or `npm i -g lighthouse`
lighthouse https://yoursite.com --view
```
**React DevTools Profiler**:
```javascript
// Wrap component to profile
import { Profiler } from 'react'
function onRenderCallback(id, phase, actualDuration) {
console.log(`${id} (${phase}) took ${actualDuration}ms`)
}
;<Profiler id="ExpensiveComponent" onRender={onRenderCallback}>
<ExpensiveComponent />
</Profiler>
```
### Backend Profiling
**Node.js Profiling**:
```bash
# Generate CPU profile
node --prof app.js
# Process profile
node --prof-process isolate-0x*.log > processed.txt
# Flame graphs (better visualization)
npm i -g 0x
0x app.js
```
**Python Profiling**:
```python
import cProfile
import pstats
# Profile function
cProfile.run('slow_function()', 'output.prof')
# Analyze
p = pstats.Stats('output.prof')
p.sort_stats('cumulative').print_stats(20)
```
### Database Profiling
**PostgreSQL**:
```sql
-- Enable query logging
ALTER DATABASE yourdb SET log_min_duration_statement = 100; -- Log queries >100ms
-- Analyze query
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users WHERE email = '[email protected]';
-- Find slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;
```
**MongoDB**:
```javascript
// Enable profiling
db.setProfilingLevel(1, { slowms: 100 })
// View slow queries
db.system.profile.find({ millis: { $gt: 100 } }).sort({ ts: -1 })
// Explain query
db.collection.find({ email: '[email protected]' }).explain('executionStats')
```
---
## Phase 2: Database Optimization
### Add Strategic Indexes
```sql
-- Before: Table scan (slow)
SELECT * FROM users WHERE email = '[email protected]';
-- Execution time: 2000ms on 1M rows
-- After: Index scan (fast)
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = '[email protected]';
-- Execution time: 5ms
-- Composite index for multi-column queries
CREATE INDEX idx_posts_user_date ON posts(user_id, created_at DESC);
SELECT * FROM posts WHERE user_id = 123 ORDER BY created_at DESC;
-- Partial index for filtered queries
CREATE INDEX idx_active_users ON users(created_at) WHERE is_active = true;
```
### Eliminate N+1 Queries
```typescript
// ❌ Bad: N+1 query problem (101 database queries)
const users = await User.findAll() // 1 query
for (const user of users) {
user.posts = await Post.findAll({ where: { userId: user.id } }) // N queries
}
// ✅ Good: Eager loading (2 queries)
const users = await User.findAll({
include: [{ model: Post }]
})
// ✅ Better: DataLoader (batching + caching)
const userLoader = new DataLoader(async userIds => {
const users = await User.findAll({ where: { id: userIds } })
return userIds.map(id => users.find(u => u.id === id))
})
```
### Query Optimization
```sql
-- Avoid SELECT *
-- ❌ Bad
SELECT * FROM users WHERE id = 1;
-- ✅ Good
SELECT id, name, email FROM users WHERE id = 1;
-- Use LIMIT
-- ❌ Bad
SELECT * FROM posts ORDER BY created_at DESC;
-- ✅ Good
SELECT * FROM posts ORDER BY created_at DESC LIMIT 20;
-- Avoid functions in WHERE clause
-- ❌ Bad (can't use index)
SELECT * FROM users WHERE LOWER(email) = '[email protected]';
-- ✅ Good (can use index)
SELECT * FROM users WHERE email = '[email protected]';
-- Store email as lowercase, or use generated column + index
```
### Connection Pooling
```typescript
// PostgreSQL connection pool
import { Pool } from 'pg'
const pool = new Pool({
max: 20, // Maximum connections
min: 5, // Minimum connections
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000 // Error if can't connect in 2s
})
// Always release connections
const client = await pool.connect()
try {
const result = await client.query('SELECT * FROM users')
return result.rows
} finally {
client.release()
}
```
---
## Phase 3: Caching Strategy
### Multi-Layer Caching
```
Browser Cache (HTTP headers)
↓
CDN Cache (Cloudflare, CloudFront)
↓
Application Cache (Redis, Memcached)
↓
Database Query Cache
↓
Database
```
### Redis Caching
```typescript
import Redis from 'ioredis'
const redis = new Redis({
maxRetriesPerRequest: 3,
enableReadyCheck: true
})
async function getUser(id: string): Promise<User> {
const cacheKey = `user:${id}`
// 1. Check cache
const cached = await redis.get(cacheKey)
if (cached) {
return JSON.parse(cached)
}
// 2. Cache miss - fetch from database
const user = await db.users.findById(id)
// 3. Store in cache (expire in 1 hour)
await redis.setex(cacheKey, 3600, JSON.stringify(user))
return user
}
// Cache invalidation
async function updateUser(id: string, data: Partial<User>) {
await db.users.update(id, data)
await redis.del(`user:${id}`) // Invalidate cache
}
```
### HTTP Caching Headers
```typescript
// Express middleware
app.use((req, res, next) => {
// Static assets: cache for 1 year
if (req.url.match(/\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$/)) {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
}
// HTML: no cache (always revalidate)
if (req.url.endsWith('.html') || req.url === '/') {
res.setHeader('Cache-Control', 'no-cache, must-revalidate')
}
// API responses: cache for 5 minutes
if (req.url.startsWith('/api/')) {
res.setHeader('Cache-Control', 'public, max-age=300')
res.setHeader('ETag', generateETag(req.url))
}
next()
})
```
### CDN Configuration
```yaml
Static Assets to CDN:
- Images: /images/**
- JavaScript: /js/**
- CSS: /css/**
- Fonts: /fonts/**
CDN Settings:
- Cache duration: 1 year (with versioned URLs)
- Gzip/Brotli compression: enabled
- Image optimization: WebP conversion
- Purge on deploy: yes (via API)
Recommended CDNs:
- Cloudflare (free tier excellent)
- CloudFront (AWS integration)
- Fastly (enterprise, very fast)
```
---
## Phase 4: Frontend Optimization
### Code Splitting & Lazy Loading
```typescript
// React lazy loading
import { lazy, Suspense } from 'react'
// ❌ Bad: Load everything upfront
import Dashboard from './Dashboard'
import AdminPanel from './AdminPanel'
// ✅ Good: Lazy load routes
const Dashboard = lazy(() => import('./Dashboard'))
const AdminPanel = lazy(() => import('./AdminPanel'))
function App() {
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/admin" element={<AdminPanel />} />
</Routes>
</Suspense>
)
}
// Next.js dynamic imports
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <LoadingSpinner />,
ssr: false // Skip SSR for this component
})
```
### Image Optimization
```jsx
// Next.js Image component (automatic optimizationRelated in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.