- Learn
- Advanced Topics
- Performance Optimization
Advanced20 min1 prerequisite
Identify and fix performance issues in AI-generated code with systematic optimization techniques.
Performance Optimization
Learn to identify and fix performance issues in AI-generated code, from client-side rendering to database queries.
Why AI Code Needs Optimization
Common AI Performance Issues
Terminal
AI tends to generate:
├── Correct but unoptimized code
├── Over-fetching data
├── Unnecessary re-renders
├── N+1 query patterns
├── Missing caching
└── Blocking operations
Example: Unoptimized vs Optimized
Terminal
// AI-generated (works but slow)
async function getUsers() {
const users = await db.users.findMany()
return users.map(user => ({
...user,
posts: await db.posts.findMany({ where: { userId: user.id } }),
comments: await db.comments.findMany({ where: { userId: user.id } })
}))
}
// Optimized (batched queries)
async function getUsers() {
const users = await db.users.findMany({
include: {
posts: true,
comments: true
}
})
return users
}
Client-Side Performance
Identifying React Re-renders
Terminal
// Install React DevTools Profiler
// Or add debug logging:
import { useEffect, useRef } from 'react'
function useRenderCount(componentName: string) {
const renderCount = useRef(0)
renderCount.current++
useEffect(() => {
console.log(`${componentName} rendered ${renderCount.current} times`)
})
}
// Usage in component
function ProductList({ products }) {
useRenderCount('ProductList')
// ...
}
Common Re-render Fixes
Terminal
// Problem: New object/array reference every render
function Parent() {
return <Child options={{ sort: 'name' }} /> // ❌ New object each render
}
// Fix: Memoize or move outside
const OPTIONS = { sort: 'name' }
function Parent() {
return <Child options={OPTIONS} /> // ✓ Stable reference
}
// Or with useMemo for dynamic values
function Parent({ sortField }) {
const options = useMemo(() => ({ sort: sortField }), [sortField])
return <Child options={options} />
}
Terminal
// Problem: Inline function props
function Parent() {
return <Button onClick={() => handleClick()} /> // ❌ New function each render
}
// Fix: useCallback
function Parent() {
const handleButtonClick = useCallback(() => {
handleClick()
}, [])
return <Button onClick={handleButtonClick} /> // ✓ Stable function
}
Optimizing Lists
Terminal
// Problem: AI often generates without keys or with index keys
{items.map((item, index) => (
<Item key={index} item={item} /> // ❌ Index as key
))}
// Fix: Use stable unique identifiers
{items.map((item) => (
<Item key={item.id} item={item} /> // ✓ Stable ID
))}
Terminal
// Problem: Large lists rendering entirely
function ProductList({ products }) {
return (
<div>
{products.map(product => <ProductCard product={product} />)}
</div>
)
}
// Fix: Virtualization for large lists
import { useVirtualizer } from '@tanstack/react-virtual'
function ProductList({ products }) {
const parentRef = useRef(null)
const virtualizer = useVirtualizer({
count: products.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 100,
})
return (
<div ref={parentRef} className="h-[600px] overflow-auto">
<div style={{ height: `${virtualizer.getTotalSize()}px` }}>
{virtualizer.getVirtualItems().map((virtualItem) => (
<ProductCard
key={products[virtualItem.index].id}
product={products[virtualItem.index]}
style={{
position: 'absolute',
top: 0,
transform: `translateY(${virtualItem.start}px)`,
}}
/>
))}
</div>
</div>
)
}
Server-Side Performance
Database Query Optimization
Terminal
// Problem: N+1 queries
async function getOrdersWithItems() {
const orders = await db.orders.findMany()
// ❌ One query per order
for (const order of orders) {
order.items = await db.orderItems.findMany({
where: { orderId: order.id }
})
}
return orders
}
// Fix: Single query with join
async function getOrdersWithItems() {
return db.orders.findMany({
include: {
items: true // ✓ Single query with join
}
})
}
Supabase Query Optimization
Terminal
// Problem: Over-fetching
const { data } = await supabase
.from('users')
.select('*') // ❌ Fetches all columns
// Fix: Select only needed columns
const { data } = await supabase
.from('users')
.select('id, name, email') // ✓ Only needed columns
Terminal
// Problem: No pagination
const { data } = await supabase
.from('products')
.select('*') // ❌ Fetches all products
// Fix: Pagination
const { data, count } = await supabase
.from('products')
.select('*', { count: 'exact' })
.range(0, 19) // ✓ First 20 products
Caching Strategies
Terminal
// Next.js fetch caching
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 } // Cache for 1 hour
})
return res.json()
}
Terminal
// React cache for deduplication
import { cache } from 'react'
export const getUser = cache(async (id: string) => {
const res = await fetch(`/api/users/${id}`)
return res.json()
})
// Called multiple times but only fetches once per request
await getUser('123')
await getUser('123') // Uses cached result
Terminal
// unstable_cache for database queries
import { unstable_cache } from 'next/cache'
const getCachedProducts = unstable_cache(
async () => {
return db.products.findMany()
},
['products'], // Cache key
{ revalidate: 3600 } // Revalidate every hour
)
Bundle Size Optimization
Analyze Bundle
Terminal
# Install bundle analyzer
npm install @next/bundle-analyzer
# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({})
# Run analysis
ANALYZE=true npm run build
Dynamic Imports
Terminal
// Problem: Large component loaded immediately
import HeavyChart from '@/components/HeavyChart'
// Fix: Lazy load
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {
loading: () => <ChartSkeleton />,
ssr: false // If chart doesn't need SSR
})
Tree Shaking
Terminal
// Problem: Importing entire library
import _ from 'lodash' // ❌ Imports all of lodash
_.debounce(fn, 300)
// Fix: Import specific function
import debounce from 'lodash/debounce' // ✓ Only imports debounce
debounce(fn, 300)
Image Optimization
Terminal
// Problem: Unoptimized images
<img src="/large-image.jpg" /> // ❌ No optimization
// Fix: Next.js Image
import Image from 'next/image'
<Image
src="/large-image.jpg"
width={800}
height={600}
alt="Description"
placeholder="blur"
blurDataURL="data:image/..."
/> // ✓ Automatic optimization
Terminal
// Lazy loading below fold
<Image
src="/image.jpg"
loading="lazy" // Default behavior
priority={false} // Don't preload
/>
// Eager loading above fold
<Image
src="/hero.jpg"
priority={true} // Preload this image
/>
Performance Prompts
Ask AI to Optimize
Terminal
"Review this code for performance issues:
[paste code]
Check for:
- Unnecessary re-renders
- N+1 queries
- Missing memoization
- Over-fetching data
- Missing pagination
- Bundle size issues
Suggest specific optimizations."
Generate Optimized Code
Terminal
"Generate a paginated data table component with:
- Server-side pagination
- Efficient re-renders (memoized rows)
- Virtualization for 1000+ rows
- Debounced search
- Optimistic UI updates"
Performance Checklist
Client-Side
Terminal
- [ ] React DevTools shows no unnecessary re-renders
- [ ] Stable references for objects/functions passed as props
- [ ] Large lists use virtualization
- [ ] Heavy components are lazy loaded
- [ ] Images use next/image with proper sizing
- [ ] Bundle analyzer shows no unexpected large imports
Server-Side
Terminal
- [ ] No N+1 query patterns
- [ ] Only needed columns selected
- [ ] Pagination implemented for lists
- [ ] Appropriate caching in place
- [ ] Database indexes for common queries
- [ ] API responses are reasonably sized
Summary
Key optimization areas:
- Re-renders: Memoize, stable references, virtualization
- Data fetching: Batched queries, select needed columns
- Caching: Next.js fetch cache, React cache, unstable_cache
- Bundle: Dynamic imports, tree shaking, analyze regularly
- Images: Next.js Image component with proper configuration
Next Steps
Learn security best practices for AI-generated code.
Mark this lesson as complete to track your progress