Skip to main content

Image Optimization

vinext uses Cloudflare Images for on-the-fly image resizing and format transcoding in production. Images are optimized at the edge with zero build-time processing.

How It Works

When using next/image, vinext:
  1. Generates an optimization URL: /_vinext/image?url=/photo.jpg&w=800&q=75
  2. Fetches the source image from the ASSETS binding
  3. Transforms via Cloudflare Images (resize, transcode, compress)
  4. Returns optimized image with Cache-Control: public, max-age=31536000, immutable
No build-time optimization or static resizing occurs.

Setup

Automatic Setup (vinext deploy)

vinext deploy configures everything automatically:
This generates:
  • ASSETS binding in wrangler.jsonc
  • IMAGES binding in wrangler.jsonc
  • Worker entry with image optimization handler

Manual Setup

1. Configure wrangler.jsonc

2. Create Worker Entry

API Reference

handleImageOptimization

Handles image optimization requests.

Parameters

request (required)
Type: Request
Incoming image optimization request.
handlers (required)
Type: ImageHandlers
Callbacks for fetching and transforming images.
handlers.fetchAsset
Fetch the source image. Typically delegates to env.ASSETS.fetch().
handlers.transformImage (optional)
Transform the image. Omit for passthrough (serves original).

Returns

Promise<Response> - Optimized image response with cache headers.

parseImageParams

Parses and validates image optimization query parameters.

Query Parameters

url (required)
Type: string
Source image path. Must be path-relative (starts with /, not //).
w (required)
Type: number
Target width in pixels. 0 = no resize.
q (optional)
Type: number
Default: 75
Quality (1-100).

Example

negotiateImageFormat

Negotiates the best output format based on the Accept header.

Returns

  • 'image/avif' if Accept includes image/avif
  • 'image/webp' if Accept includes image/webp
  • 'image/jpeg' otherwise

Example

Constants

IMAGE_OPTIMIZATION_PATH

The pathname that triggers image optimization.

IMAGE_CACHE_CONTROL

Standard Cache-Control header for optimized images. Optimized images are immutable because the URL encodes the transform params.

Usage in Components

Use next/image normally:
vinext automatically generates optimization URLs:

Remote Images

Remote images work via @unpic/react which auto-detects 28 CDN providers:
Configure allowed patterns in next.config.js:

Format Negotiation

The handler automatically serves the best format based on the Accept header:
  • AVIF (smallest, newer browsers)
  • WebP (smaller, wide support)
  • JPEG (fallback)
Cloudflare’s edge cache stores one variant per format, so the same image URL can return different formats to different clients.

Security

Path Validation

Only path-relative URLs are allowed. This prevents:
  • Open redirect: ?url=https://evil.com/phishing
  • SSRF: ?url=http://internal-service/admin
  • Protocol smuggling: ?url=data:image/svg+xml,...
Valid:
  • ?url=/photo.jpg
  • ?url=/images/profile.png
Invalid (returns 400):
  • ?url=https://example.com/photo.jpg
  • ?url=//example.com/photo.jpg
  • ?url=data:image/svg+xml,...

Width/Quality Limits

The handler validates:
  • Width: Must be >= 0. 0 = no resize.
  • Quality: Must be 1-100.
Invalid values return 400 Bad Request.

Fallback Behavior

If transformImage is omitted or throws an error, the handler serves the original image with cache headers:
This is useful for:
  • Development server (no Images binding)
  • Non-Cloudflare deployments
  • Debugging

Development vs Production

Development

In dev mode, images are served as passthroughs (no optimization). The transformImage callback is omitted:

Production

In production on Workers, images are optimized via Cloudflare Images:

Example: Custom Watermarking

Add custom image processing logic:
See Cloudflare Images API for transform options.

Limitations

  • No build-time optimization: Images are optimized at request time, not build time
  • No static resizing: next export doesn’t pre-generate responsive variants
  • No blur placeholders: placeholder="blur" is not supported
  • No sizes auto-detection: You must provide the sizes prop manually for responsive images