Your Next.js app works fine at 100 users. But what happens at 10,000? This guide covers the strategies we apply to ensure Next.js apps scale gracefully.
1. Caching Strategy: The Three Levels
Next.js offers three caching levels, and using all three strategically is essential for scale.
Level 1: Request Memoization
React automatically deduplicates fetch requests made during a single render:
// These two calls in different components make only ONE network request
const dataA = await fetch('/api/user/123'); // in ComponentA
const dataB = await fetch('/api/user/123'); // in ComponentB — cached!Level 2: Data Cache (Next.js)
// Cache this fetch result for 1 hour
const data = await fetch('/api/products', { next: { revalidate: 3600 } });Level 3: Full Route Cache (ISR)
export const revalidate = 60; // Regenerate page every 60 seconds2. Database Query Optimization
The single biggest Next.js performance bottleneck is usually the database. Key principles:
- Use select() to fetch only needed columns, not `SELECT *`.
- Add database indexes on columns used in WHERE and ORDER BY clauses.
- Use Supabase's connection pooling via pgBouncer for serverless environments.
// ❌ Slow: fetches all columns
const { data } = await supabase.from('products').select('*');
// ✅ Fast: fetches only needed columns
const { data } = await supabase.from('products').select('id, name, price, slug');3. Image Optimization
- Use Next.js's `<Image>` component for automatic WebP conversion and lazy loading.
- Set `sizes` prop correctly: `"(max-width: 768px) 100vw, 50vw"`.
- Use a CDN-backed storage solution (Supabase Storage, Cloudflare R2).
4. Edge Runtime for Global Performance
Deploy latency-sensitive API routes to the Edge:
export const runtime = 'edge'; // Runs in 100+ edge locationsConclusion: Scaling Next.js is about applying the right caching at each layer, optimizing database queries, and pushing computation to the edge.

