EdgeCases Logo
Apr 2026
Vercel
Deep
9 min read

Vercel Image Optimization Costs at Scale

When next/image optimization becomes expensive at scale

vercel
image-optimization
next/image
cost-optimization
cdn
pricing
production
performance

The Hidden Cost of Optimized Images

Next.js next/image component automatically optimizes images on Vercel: resizing, format conversion (WebP/AVIF), quality adjustment, and CDN delivery. It's magical—until your bill arrives.

Image optimization isn't free. Every transformed image incurs costs: transformation processing, CDN bandwidth, and storage. At scale, these costs compound into thousands of dollars monthly.

The worst part? Costs sneak up on you. Development shows cached images, production hits real limits. Preview deployments spin up unnecessary transformations. Dynamic routes generate infinite image variants.

How Vercel Bills Image Optimization

Vercel's image optimization pricing has two components:

  1. Source Image Transformations: Each unique source image that gets optimized counts against your plan limits
  2. Fast Data Transfer + Edge Requests: Delivering optimized images from Vercel's CDN to clients

Plan Limits (2026):

  • Hobby: 1,000 source image optimizations/month (free)
  • Pro: 5,000 source image optimizations/month ($20/month)
  • Enterprise: Custom limits with overage pricing

Overage: $5 per additional 1,000 source image optimizations.

Example: You optimize 28,000 images. Pro plan covers 5,000. You pay $5 × (28,000 - 5,000) / 1,000 = $115 in overage charges. Plus the $20 base fee. Total: $135/month for image optimization alone.

The Real Cost Drivers

Dynamic Routes = Infinite Image Variants

Dynamic routes like /products/[id] generate unique images for each product. If you have 10,000 products and 3 image sizes per product, that's 30,000 potential transformations.

// ❌ Generates unique transformations for every product
export default async function ProductPage({ params }) {
  const product = await getProduct(params.id);
  return (
    <Image
      src={product.image}
      width={800}
      height={600}
      alt={product.name}
    />
  );
}

Each unique combination of source URL, width, height, and quality triggers a new transformation.

Preview Deployments Waste Money

Every preview deployment re-optimizes images. If your team makes 50 deployments/day and each optimizes 200 images, that's 10,000 transformations/day—300,000/month. All waste.

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Skip image optimization in preview deployments
  images: {
    unoptimized: process.env.VERCEL_ENV === 'preview',
  },
};

Multiple Formats = Multiple Transformations

Next.js can serve multiple formats (WebP, AVIF, JPEG). Each format transformation counts separately:

// ❌ Each browser request triggers a separate transformation
images: {
  formats: ['image/avif', 'image/webp'],
}

// ✅ Serve single optimized format
images: {
  formats: ['image/webp'], // AVIF has limited browser support
}

If Chrome requests AVIF and Safari requests WebP, you're charged for two transformations of the same image.

Short Cache TTLs = Repeated Work

Vercel caches optimized images, but cache expiration triggers re-optimization. Default cache TTL is 1 year for static imports, but remote URLs default to the remote server's cache headers.

// ❌ Remote images with short cache TTL
<Image src="https://example.com/image.jpg" />

// ✅ Force long cache TTL
<Image
  src="https://example.com/image.jpg"
  loader={({ src, width, quality }) => {
    return `${src}?w=${width}&q=${quality || 75}&maxAge=31536000`;
  }}
/>

Cost Optimization Strategies

1. Set minimumCacheTTL

Force long cache durations for images that don't change frequently:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    minimumCacheTTL: 2678400, // 31 days in seconds
  },
};

This reduces repeated transformations by ensuring images stay cached longer. Set to 31 days (2,678,400 seconds) for most use cases.

2. Use Static Imports

Static imports automatically set Cache-Control: public, max-age=31536000, immutable (1 year cache):

// ✅ Static import = 1-year cache
import heroImage from './hero.jpg';

export default function HomePage() {
  return <Image src={heroImage} alt="Hero" />;
}

Remote URLs inherit cache headers from the origin server. If those headers are short, images re-optimize frequently.

3. Limit Image Formats

Most browsers support WebP. AVIF support is growing but still limited (~75% as of 2026). Stick to WebP unless you have specific AVIF requirements:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    formats: ['image/webp'],
  },
};

This cuts transformation count in half for most users.

4. Disable Optimization for Preview Deployments

Preview deployments don't need optimized images. Disable them to save costs:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    unoptimized: process.env.VERCEL_ENV === 'preview',
  },
};

Preview deployments will serve original images (larger files, slower), but you avoid optimization costs entirely.

5. Pre-Optimize Images at Build Time

For static sites, pre-optimize images during build and serve them as static assets:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
};

Limiting the number of device sizes and image sizes reduces the total number of unique transformations generated at build time.

Monitoring Your Usage

Vercel provides image optimization metrics in the dashboard. Check these regularly:

  1. Go to your project's Analytics tab
  2. Filter by "Image Optimization" events
  3. Monitor unique source image count vs. plan limit
  4. Track CDN bandwidth for Fast Data Transfer costs

Set up alerts when you approach 80% of your limit to avoid surprise overage charges.

When to Use an External Image CDN

If image optimization costs exceed $100/month consistently, consider an external image CDN:

  • Cloudflare Images: $5/month + bandwidth
  • Cloudinary: $99/month for 25,000 transformations
  • Imgix: $25/month for 10,000 transformations
  • Self-hosted: Vercel Blob Storage + custom optimization

External CDNs often offer better pricing at scale, but you lose the convenience of next/image integration.

Cost Comparison Example

ScenarioMonthly ImagesVercel CostExternal CDN Cost
Small blog500 images$0 (Hobby plan)$20 (Cloudflare)
E-commerce (1K products)10,000 images$45 (Pro + overage)$25 (Imgix)
E-commerce (10K products)100,000 images$520 (Pro + overage)$99 (Cloudinary)
Large platform1M images$5,020 (Enterprise)$499 (Custom)

External CDNs become cost-effective around 10,000+ images/month. Below that, Vercel's included optimization is cheaper and more convenient.

Production Checklist

Before deploying to production, verify these optimizations are in place:

  • minimumCacheTTL set to 31+ days
  • ✅ Image formats limited to WebP (or WebP + AVIF with care)
  • ✅ Preview deployments have optimization disabled
  • ✅ Device and image sizes are limited to realistic values
  • ✅ Remote images use cache-busting URLs or long TTL headers
  • ✅ Analytics alerts configured for 80% plan usage
  • ✅ External CDN evaluated if costs exceed $100/month

Image optimization is powerful, but costs scale with usage. Monitor, optimize, and migrate when necessary. Review your Vercel bill regularly to catch optimization costs before they spiral.

Advertisement

Related Insights

Explore related edge cases and patterns

Next.js
Surface
Vercel Blob Storage: When It Makes Sense (and When It Doesn't)
6 min
Next.js
Deep
Neon on Vercel: The Connection Pooling Maze
7 min
Next.js
Expert
Vercel Billing Demystified: Edge Requests, Function Duration, and ISR Costs
8 min
Next.js
Expert
Vercel Image Build Bottleneck: CDN Migration and OG Generation
8 min

Advertisement