- Performance Optimization
- When to use this skill
- Slow page loads
-
- low Lighthouse score
- Slow rendering
-
- delayed user interactions
- Large bundle size
-
- increased download time
- Slow queries
- database bottlenecks Instructions Step 1: Measure performance Lighthouse (Chrome DevTools) :
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): import { 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 ) ; Step 2: Optimize React React.memo (prevent unnecessary re-renders) : // ❌ 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 : function 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 : import { 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
) ; } Step 3: Optimize bundle size Webpack Bundle Analyzer : npm install --save-dev webpack-bundle-analyzer
package.json
{ "scripts" : { "analyze" : "webpack-bundle-analyzer build/stats.json" } } Tree Shaking (remove unused code) : // ❌ Bad: import entire library import _ from 'lodash' ; // ✅ Good: import only what you need import debounce from 'lodash/debounce' ; Dynamic Imports : // ✅ Load only when needed button . addEventListener ( 'click' , async ( ) => { const { default : Chart } = await import ( 'chart.js' ) ; new Chart ( ctx , config ) ; } ) ; Step 4: Optimize images Next.js Image component : import 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 : < picture
< source srcset = " image.webp " type = " image/webp "
< source srcset = " image.jpg " type = " image/jpeg "
< img src = " image.jpg " alt = " Fallback "
</ picture
Step 5: Optimize database queries Fix the N+1 query problem : // ❌ 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 : -- 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) : async 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 ; } Output format Performance optimization checklist
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
- Constraints
- Required rules (MUST)
- Measure first
-
- profile, don't guess
- Incremental improvements
-
- optimize one thing at a time
- Performance monitoring
-
- track continuously
- Prohibited items (MUST NOT)
- Premature optimization
-
- don't optimize when there is no bottleneck
- Sacrificing readability
-
- don't make code complex for performance
- Best practices
- 80/20 rule
-
- 80% improvement with 20% effort
- User-centered
-
- focus on improving real user experience
- Automation
-
- performance regression tests in CI
- References
- web.dev/vitals
- React Optimization
- Webpack Bundle Analyzer
- Metadata
- Version
- Current version
-
- 1.0.0
- Last updated
-
- 2025-01-01
- Compatible platforms
- Claude, ChatGPT, Gemini