Guide for using Netlify Image CDN for image optimization and transformation. Use when serving optimized images, creating responsive image markup, setting up user-uploaded image pipelines, or configuring image transformations. Covers the /.netlify/images endpoint, query parameters, remote image allowlisting, clean URL rewrites, and composing uploads with Functions + Blobs.
Transform images by requesting /.netlify/images with query parameters. No function or file authoring required — it's a built-in edge endpoint.
# resize + crop to a 50px square, retain left side, convert to webp at q=80
curl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fit=cover&w=50&h=50&position=left&fm=webp&q=80'
There is no legacy/deprecated form — the endpoint above is the only programmatic surface. Use framework image components where available (below) rather than hand-building URLs.
GET /.netlify/images?url=<source>&...
| Param | Values | Notes |
|---|---|---|
url | relative path or full remote URL | REQUIRED. Only required param. |
w | integer px | width |
h | integer px | height |
fit | contain (default), cover, fill | resize behavior |
position | center (default), top, bottom, left, right | only applies when fit=cover |
fm | avif, jpg, png, webp, gif, blurhash | output format; webp/gif can be animated |
q | integer 1–100 (default 75) | only for avif, jpg, gif, webp |
fit behaviorfit= | aspect ratio kept | crops excess | returns exact dimensions |
|---|---|---|---|
contain | yes | no | no — one dimension may be smaller |
cover | no | yes | yes — scaled proportionally, then cropped |
fill | no | no | yes — stretched/squished if needed |
fit=cover requires BOTH w and h. Supplying only one silently misbehaves.contain with one dimension calculates the other to preserve aspect ratio.url, no size/format): image is unchanged in size/shape but still reformatted to avif/webp based on the browser's Accept header.fm specified → webp if accepted, else avif if accepted, else original.fm=blurhash returns a BlurHash text string, not image bytes. Pointing <img src> or a CSS background at it renders nothing. Fetch the string server-side/ahead of time, decode it client-side with a BlurHash library (https://blurha.sh), then load the real image as a separate request without fm=blurhash.404.200 with content + content-type.304.Remote url values require allowlisting the domain in netlify.toml:
[images]
remote_images = ["https://my-images.com/.*", "https://animals.more-images.com/[bcr]at/.*"]
Then percent-encode the remote URL and request it:
const src = `/.netlify/images?url=${encodeURIComponent("https://my-images.com/owl.jpeg")}`;
encodeURIComponent the remote URL before placing it in url — URLs containing ? or & break otherwise.remote_images patterns, escape only the dot: 'https://example\.com/.*'. Forward slashes are NOT regex metacharacters — do not write https:\/\/.Authorization or Cookie headers to remote sources. For auth-required images use self-authorizing URLs (e.g. S3 presigned URLs) and make sure your remote_images pattern matches them.Reuse the same params across many images via a redirect:
_redirects:
/transform-small/* /.netlify/images?url=/:splat&w=50&h=50 200
netlify.toml:
[[redirects]]
from = "/transform-small/*"
to = "/.netlify/images?url=/:splat&w=50&h=50"
status = 200
Then GET /transform-small/owl.jpeg yields a 50×50 transform. Avoid cross-site redirects for transformations — they hurt performance.
_headers:
/source-images/*
Cache-Control: public, max-age=604800, must-revalidate
Cache-Control on source images applies only to browsers/CDNs in front of Netlify, not the Netlify Cache itself.Use the framework's native image component/handling; it wires to Image CDN automatically. Configure the remote allowlist per framework:
| Framework | Prerequisite | Remote allowlist |
|---|---|---|
| Angular | none — NgOptimizedImage auto-uses it | [images] remote_images in netlify.toml |
| Astro | none — <Image /> auto-uses it | image.domains / image.remotePatterns in astro.config.mjs |
| Nuxt | none — nuxt/image auto-uses it | image.domains in nuxt.config.ts |
| Next.js | Next 13.5+ and adapter v5 | remotePatterns in next.config.js |
| Gatsby | env NETLIFY_IMAGE_CDN=true + Contentful/Drupal/WordPress source plugin | [images] remote_images in netlify.toml |
Run netlify dev (Netlify CLI) to test transformations locally — it mimics production including Image CDN.
404 on /.netlify/images almost always means a framework dev server (vite, next dev, astro dev) is running instead of netlify dev. The endpoint, [images] allowlisting, and image redirects only exist under netlify dev. The URL itself is usually fine.Transformed results are uniquely cached on Netlify's edge. Atomic deploys are respected: changing a source image in a new deploy re-runs transformations on new requests so stale assets aren't served.
For user-uploaded image pipelines (Functions + Blobs + Image CDN composed), see references/user-uploads.md in this skill.
These are org conventions, not docs facts — merged into the rendered skill by ctx-gen and never generated. Owned by the skills maintainer.
references/user-uploads.md in this skill — an authored
guide with no single docs source.url
parameter (encodeURIComponent) — URLs containing ? or & break
otherwise.fm=blurhash returns a BlurHash TEXT string, not image bytes. Pointing an
<img src> (or CSS background) at it renders nothing — fetch the string
ahead of time, decode it client-side with a BlurHash library, and load the
real image as a separate request without fm=blurhash./.netlify/images almost always means a framework dev
server (vite, next dev, astro dev) is running instead of
netlify dev — the endpoint, [images] allowlisting, and image redirects
only exist under netlify dev. The URL itself is usually fine.remote_images patterns, the meaningful regex escape is the dot;
forward slashes are not metacharacters — do not write https:\/\/.
In netlify.toml, use a single-quoted literal string
('https://example\.com/.*') or double the backslash in a
double-quoted string ("https://example\\.com/.*") — a bare \.
inside double quotes is invalid TOML.skillbazaar install netlify-image-cdn --agent claudeSign in (free) to install skills with the CLI.
Author
@netlify
on GitHub
Published by