🛠️ image-pipeline

How images are fetched, resized, cached, and what limits/allow-lists apply

Image Pipeline

AstroMerchant lets you paste any HTTPS image URL (from your CDN, S3, ImageKit, Unsplash, etc.).
We generate responsive variants (AVIF/WebP with a JPEG or PNG fallback), add intrinsic width/height to prevent CLS, and cache results.

There are two paths images can take:

  • Astro components (product grids, blog cards, etc.) use Astro’s <Image /> via Netlify Image CDN at /_image (edge-cached).
  • React/client components (e.g., search grid) use our SSR endpoint /api/img (long-lived cache headers).

Supported input formats

  • jpg/jpeg, png, webp, avif, svg, gif, tiff, heic/heif
  • ⚠️ Animated formats are treated as static (first frame).
  • ✅ Only HTTPS sources are accepted.

Output formats

By default components serve:

formats={['avif','webp','jpeg']}

Browsers pick the best option via <picture>.
Transparency: If a source has alpha and jpeg is requested, the pipeline automatically serves PNG for that variant to preserve transparency.


Caching

  • /_image (Astro + Netlify Image CDN): transformed assets are edge-cached.
  • /api/img (SSR endpoint): responses include
    Cache-Control: public, max-age=31536000, immutable
    so unique variants by querystring are cacheable.

Domain allow-list (remote images)

Remote hosts must be allowed, otherwise requests are blocked.

Netlify (for /_image)

netlify.toml

[images]
  remote_images = ["ik.imagekit.io/*", "images.unsplash.com/*"]

Local dev .env

NETLIFY_IMAGE_CDN_ALLOWED_REMOTE_DOMAINS=ik.imagekit.io,images.unsplash.com

/api/img endpoint

Uses the same env var (or IMG_ALLOWED_DOMAINS) to restrict hosts:

# either of these is supported
NETLIFY_IMAGE_CDN_ALLOWED_REMOTE_DOMAINS=ik.imagekit.io,images.unsplash.com
IMG_ALLOWED_DOMAINS=*.examplecdn.com,assets.myapp.com/*

If the list is empty, /api/img allows all HTTPS hosts (dev-friendly).
If set, only matching hosts are allowed (supports exact and *.domain.com).


Size limits (safety & performance)

  • Max requested width: 4096px (MAX_W = 4096)
    Larger requests are clamped.
  • Max input pixels: ~16k × 16k (limitInputPixels = 268435456)
    Prevents pathological source files.
  • No enlargement: we don’t upscale beyond the source size.

Extremely large/invalid sources may return a 4xx/5xx error.


  • Product heroes & blog headers: 1600–2400px wide
  • Gallery/detail images: 1200–1600px wide
  • Thumbnails/cards: ≤ 800px (we downsize anyway)

Typical usage

Astro components (already wired in the theme):

<Image
  src={imageUrl}
  alt={title}
  widths={[640,768,1024,1280,1600,1920]}
  sizes="(min-width:1024px) 50vw, 100vw"
  formats={['avif','webp','jpeg']}
/>

React components (use our API route):

const u = encodeURIComponent(src);
const url = `/api/img?u=${u}&w=640&f=webp`;

// Optional 2x srcset for crisp thumbs:
const srcset = `/api/img?u=${u}&w=640&f=jpeg 1x, /api/img?u=${u}&w=1280&f=jpeg 2x`;

Common errors & fixes

  • “Host not allowed” → Add the domain to the allow-list (see above) & restart dev.
  • “Only https:// images are allowed” → Use HTTPS URLs.
  • “Upstream fetch failed” → Source URL is invalid/private/down; verify it opens in a browser.
  • Blank/stub images in dev → Ensure .env allow-list is set; restart astro dev; hard refresh.

Changing the max width (advanced)

If you need outputs wider than 4096px, raise MAX_W in both:

  • src/image/netlify-universal-service.ts
  • src/pages/api/img.ts

Larger outputs increase CPU/memory usage and response time. Change with care.


TL;DR for buyers

  • Paste HTTPS image URLs from your CDN/storage.
  • We auto-generate modern formats and responsive sizes with proper width/height to avoid layout shift.
  • There’s a max output width of 4096px; huge source files are limited for safety.
  • If a host is blocked, add it to the allow-list (ik.imagekit.io, images.unsplash.com, etc.).

Free shipping over £60.00

Delivered with care. No code needed.