Images are the heaviest and most LCP-affecting element on a web page. Optimize them and Core Web Vitals rise, improving SEO and bounce rate. On the other hand, misuse them and the bill spikes from transformation billing. Reconciling these two is the crux of Vercel image optimization.
This article summarizes the use of next/image and cost optimization, faithful to the official specs of Vercel Image Optimization. For the full picture, see the Vercel production-operations guide; for cost, Active CPU optimization.
The mechanism: dynamic transformation → CDN cache
Use next/image (Astro/Nuxt have equivalent components too) and Vercel dynamically optimizes the source image.
- Use a bare
imgtag and optimization is bypassed, serving the source image as-is. - Use the
Imagecomponent and it rides Vercel's optimization pipeline — conversion to AVIF/WebP, resizing to the device width, and CDN caching. - Cache states:
- HIT: served from cache (no transformation)
- MISS: transform → cache → serve (transformation + cache write billing)
- STALE: serve from cache while re-transforming in the background (same as above)
// app/page.tsx — next/image の基本
import Image from "next/image";
import hero from "@/public/hero.jpg"; // ローカル画像(ビルド時に解析)
export default function Page() {
return (
<Image
src={hero}
alt="製品のヒーロー画像" // a11y:意味のある alt を必ず
priority // LCP 画像は priority で先読み
sizes="(max-width: 768px) 100vw, 50vw" // レスポンシブの幅指定
/>
);
}
An a11y essential:
altisn't decoration. Give meaningful images analtdescribing the content, and decorative imagesalt="". It works for both the experience of screen-reader users and image SEO (web accessibility).
Configuration: narrow permissions with remotePatterns / localPatterns
State in next.config.ts which image sources may be optimized. Not allowing unlimited is important for both security and cost.
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
// ローカル(public 配下)
localPatterns: [{ pathname: "/assets/images/**", search: "" }],
// リモート(外部ホスト)
remotePatterns: [
{
protocol: "https",
hostname: "cdn.example.com",
// 自分が所有しないホストは、乱用防止にアカウントID等を含める
pathname: "/account123/**",
search: "",
},
],
// 変換のバリエーションを絞る=キャッシュ効率とコストに効く
formats: ["image/avif", "image/webp"],
qualities: [75], // 品質を1つに固定するとキャッシュキーが減る
},
};
export default nextConfig;
Abuse prevention: when allowing a
hostnameyou don't own, include an account ID, etc., in thepathnameto limit to your own source only. Widening the wildcard too much risks having your billing inflated by third-party transformations.
The cache key and retention
Optimized images are cached on the CDN, and if the cache key is the same, the transformation isn't re-run (= not billed). The key is:
- Project ID
q(quality 1–100)w(width px)url(a content hash for local, the absolute URL for remote)Acceptheader (normalized)
Retention:
| Type | Retention |
|---|---|
| Local image | Up to 31 days on the CDN |
| Remote image | The larger of the upstream Cache-Control max-age or minimumCacheTTL (default 3600s) |
A redeploy doesn't invalidate the cache. Invalidate local images by "swapping the contents under the same name and redeploying," or by manual/programmatic purge. Once a remote image is cached, the old version keeps being served until expiry or purge. "I swapped the image but it's still old" is caused by this.
The transformation URL format
The Image component replaces src with an optimization URL.
- Next.js:
/_next/image?url={src}&w=3840&q=75 - Nuxt/Astro, etc.:
/_vercel/image?url={src}&w=3840&q=75
Cost optimization: don't make the bill spike
Image optimization is a regular "main cause of increased billing." In effective order.
① Don't optimize images that shouldn't be optimized
The following pass through with unoptimized and use no transformation quota.
- Icons/thumbnails under 10KB (already small)
- Animated images like GIF
- SVG (vector; not a transformation target)
- Frequently changing images (caching doesn't work and transformations keep running)
// 小さいアイコンや SVG は最適化しない
<Image src="/icon.svg" alt="" width={24} height={24} unoptimized />
② Narrow the variations
The cache key grows with the combination of q, w, and Accept. Fixing qualities to one (e.g. 75) and narrowing sizes/deviceSizes to only the needed widths reduces the number of unique transformations = billing, and raises the HIT rate.
③ Make caching effective
- For remote images, extend
minimumCacheTTLto reduce re-transformations (a trade-off with update frequency). - Transformation results persist across deploys, so don't purge unnecessarily.
④ See what's being consumed
In Observability's Image Optimization Insights, check the number of transformations, cache read/write, and Fast Data Transfer to identify heavy spots (observability).
When to use / not use
| Should optimize | No need to optimize |
|---|---|
| Product photos / hero images (large, high quality) | Icons under 10KB |
| User-uploaded images | Animated GIF |
| Responsive images whose width changes | SVG (vector) |
| Photo portfolios, etc., where the image is the star | Frequently changing images |
For user-uploaded images, the staple combination is to store with Vercel Blob (client upload) and optimize the display with
next/image'sremotePatterns.
Production checklist (image optimization)
- Optimize photos/hero/uploaded images with
next/image - Set
altby meaning (a11y, image SEO) -
priorityon the LCP image,sizesfor responsiveness -
unoptimizedfor small icons/SVG/GIF/frequently updated - Limit sources with
remotePatterns/localPatterns, narrow the pathname for external - Narrow the variations of
qualitiesand width (HIT rate ↑, billing ↓) - Understand cache invalidation (same-name swap or purge) when replacing images
- Monitor the number of transformations and transfer volume in Observability
Summary
Image optimization is an area that creates "speed (CWV, SEO)" and "cost" at the same time.
next/imagefor AVIF/WebP conversion, responsiveness, CDN caching- Understand the cache key (
q/w/url/Accept) and retention - Cost is ① don't optimize unneeded images ② narrow the variations ③ make caching effective
- Limit sources with
remotePatterns; a redeploy doesn't clear the cache - Monitor consumption in Observability, and measure → optimize
I take on, as a project, tuning that raises CWV while keeping image cost down. This cluster's starting point is the Vercel production-operations guide.
This article is based on the Vercel Image Optimization official documentation (as of June 2026). Specs, billing, and limits are updated, so confirm the latest values officially at production adoption.