← NetlifyCONTENT HISTORY

Update to Netlify

Snapshot Oct 7, 2026 · 00:02 UTC · version 1.6.0

Collection source: downloaded plugin package. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.

WHAT CHANGED · RULE-BASED ANALYSIS

Instructions updated for netlify-image-cdn

Instruction wording changed from “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 ...” to “Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), genera...”. 109 additional added or edited lines are in the evidence.

Observed in instructions or declared skills. Runtime behavior has not been tested.

Product description

Before

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 ...

After

Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), genera...

Skill instructions

Before

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 ...

After

Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), genera...

Supporting files

Before

[{"relative_path":"LICENSE.txt","size_in_bytes":10776},{"relative_path":"agents/openai.yaml","size_in_bytes":331},{"relative_path":"assets/netlify-small.svg","size_in_bytes":1291},{"relative_path":"assets/netlify.png","size_in_bytes":268...

After

[{"relative_path":"references/user-uploads.md","size_in_bytes":4815}]

Compare saved observations

Download comparison JSON
Full technical diff · 3 changed fields

changed /description

BEFORE
"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."
AFTER
"Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), generating thumbnails or blur placeholders, serving remote/third-party images through the CDN, allowlisting remote domains in netlify.toml, setting up image redirects or cache headers, building user-uploaded image pipelines, or debugging a 404 on /.netlify/images. Also covers framework image handling for Angular/Astro/Gatsby/Next.js/Nuxt."

changed /included_files

BEFORE
[
  {
    "relative_path": "LICENSE.txt",
    "size_in_bytes": 10776
  },
  {
    "relative_path": "agents/openai.yaml",
    "size_in_bytes": 331
  },
  {
    "relative_path": "assets/netlify-small.svg",
    "size_in_bytes": 1291
  },
  {
    "relative_path": "assets/netlify.png",
    "size_in_bytes": 2686
  },
  {
    "relative_path": "references/user-uploads.md",
    "size_in_bytes": 4815
  }
]
AFTER
[
  {
    "relative_path": "references/user-uploads.md",
    "size_in_bytes": 4815
  }
]

changed /skill_md_contents

BEFORE
"---\nname: netlify-image-cdn\ndescription: 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.\n---\n\n# Netlify Image CDN\n\nEvery Netlify site has a built-in `/.netlify/images` endpoint for on-the-fly image transformation. No configuration required for local images.\n\n## Basic Usage\n\n```html\n<img src=\"/.netlify/images?url=/photo.jpg&w=800&h=600&fit=cover&q=80\" />\n```\n\n## Query Parameters\n\n| Param | Description | Values |\n|---|---|---|\n| `url` | Source image path (required) | Relative path or absolute URL |\n| `w` | Width in pixels | Any positive integer |\n| `h` | Height in pixels | Any positive integer |\n| `fit` | Resize behavior | `contain` (default), `cover`, `fill` |\n| `position` | Crop alignment (with `cover`) | `center` (default), `top`, `bottom`, `left`, `right` |\n| `fm` | Output format | `avif`, `webp`, `jpg`, `png`, `gif`, `blurhash` |\n| `q` | Quality (lossy formats) | 1-100 (default: 75) |\n\nWhen `fm` is omitted, Netlify auto-negotiates the best format based on browser support (preferring `webp`, then `avif`).\n\n## Remote Image Allowlisting\n\nExternal images must be explicitly allowed in `netlify.toml`:\n\n```toml\n[images]\nremote_images = [\"https://example\\\\.com/.*\", \"https://cdn\\\\.images\\\\.com/.*\"]\n```\n\nValues are regex patterns.\n\n## Clean URL Rewrites\n\nCreate user-friendly image URLs with redirects:\n\n```toml\n# Basic optimization\n[[redirects]]\nfrom = \"/img/*\"\nto = \"/.netlify/images?url=/:splat\"\nstatus = 200\n\n# Preset: thumbnail\n[[redirects]]\nfrom = \"/img/thumb/:key\"\nto = \"/.netlify/images?url=/uploads/:key&w=150&h=150&fit=cover\"\nstatus = 200\n\n# Preset: hero\n[[redirects]]\nfrom = \"/img/hero/:key\"\nto = \"/.netlify/images?url=/uploads/:key&w=1200&h=675&fit=cover\"\nstatus = 200\n```\n\n## Caching\n\n- Transformed images are cached at the CDN edge automatically\n- Cache invalidates on new deploys\n- Set cache headers on source images to control caching:\n\n```toml\n[[headers]]\nfor = \"/uploads/*\"\n[headers.values]\nCache-Control = \"public, max-age=31536000, immutable\"\n```\n\n## User-Uploaded Images\n\nCombine **Netlify Functions** (upload handler) + **Netlify Blobs** (storage) + **Image CDN** (serving/transforming) to build a complete user-uploaded image pipeline. See [references/user-uploads.md](references/user-uploads.md) for the full pattern.\n\n## Bundled References (Load As Needed)\n\n- [User uploads pipeline](references/user-uploads.md)\n"
AFTER
"---\nname: netlify-image-cdn\ndescription: Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), generating thumbnails or blur placeholders, serving remote/third-party images through the CDN, allowlisting remote domains in netlify.toml, setting up image redirects or cache headers, building user-uploaded image pipelines, or debugging a 404 on /.netlify/images. Also covers framework image handling for Angular/Astro/Gatsby/Next.js/Nuxt.\n---\n\n# Netlify Image CDN\n\nTransform images by requesting the endpoint with a `url` query parameter. This is the current and only documented surface — there is no legacy form.\n\n```\nGET /.netlify/images?url=<source>[&w=][&h=][&fit=][&position=][&fm=][&q=]\n```\n\n```bash\n# resize a deployed image to 50px wide\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&w=50'\n```\n\n`url` is required; all other parameters are optional.\n\n## Query parameters\n\n| Parameter | Purpose | Values | Default |\n|-----------|---------|--------|---------|\n| `url` | Source asset (required) | Relative path or remote URL | — |\n| `w` | Width in pixels | Integer | — |\n| `h` | Height in pixels | Integer | — |\n| `fit` | Resize behavior | `contain`, `cover`, `fill` | `contain` |\n| `position` | Crop anchor when `fit=cover` | `top`, `bottom`, `left`, `right`, `center` | `center` |\n| `fm` | Output format | `avif`, `jpg`, `png`, `webp`, `gif`, `blurhash` | content-negotiated |\n| `q` | Quality for lossy output | Integer `1`–`100` | `75` |\n\n## Common transformations\n\n```bash\n# resize + crop to a 50px square, retaining the left side\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fit=cover&w=50&h=50&position=left'\n\n# convert JPEG to PNG (response carries content-type: image/png)\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=png'\n\n# convert JPEG to AVIF at medium quality\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=avif&q=50'\n```\n\n### fit behavior\n\n- **`contain` (default):** maintains aspect ratio; one dimension may come back smaller than requested. Supply one dimension and the other is computed.\n- **`cover`:** fills exactly, cropping excess. **Requires BOTH `w` and `h`** — omitting either is invalid. Use `position` to choose what's retained.\n- **`fill`:** fills exactly, stretching/squishing if aspect ratios differ.\n\n### Format notes\n\n- `q` applies only when output is `avif`, `jpg`, `gif`, or `webp`.\n- `webp` and `gif` can be static or animated.\n- If `fm` is omitted, format is content-negotiated from the `Accept` header: `webp` if accepted, else `avif` if accepted, else the original format. A source-only request (no other params) still converts to `webp`/`avif` but keeps size and shape.\n\n## Remote source images\n\nRemote sources must be allowlisted in `netlify.toml` before transformation, or the request fails.\n\n```toml\n[images]\n  remote_images = ['https://my-images\\.com/.*', 'https://animals.more-images.com/[bcr]at/.*']\n```\n\nPercent-encode remote source URLs before placing them in the `url` parameter with `encodeURIComponent` — a URL containing `?` or `&` breaks otherwise.\n\n```js\nconst src = `/.netlify/images?url=${encodeURIComponent('https://my-images.com/owl.jpeg?v=2')}&w=400`;\n```\n\nConstraints:\n- Remote sources must be **publicly accessible**.\n- Credential-bearing headers (`Authorization`, `Cookie`) are **NOT forwarded** when fetching a remote source. For authenticated sources, use URLs that carry their own authorization (e.g. S3 presigned URLs) and make sure your `remote_images` patterns match those full URLs.\n\n### remote_images regex escaping\n\nThe only meaningful escape is the literal dot (`\\.`). Forward slashes are NOT metacharacters — never write `https:\\/\\/`. In `netlify.toml`, use single-quoted literal strings (`'https://example\\.com/.*'`) or double the backslash in double-quoted strings (`\"https://example\\\\.com/.*\"`). A bare `\\.` inside double quotes is invalid TOML.\n\n## Response codes\n\n- Invalid transformation parameter values → `404`.\n- Valid new transformation → `200` with content and matching `content-type`.\n- Previously transformed (cached) image → `304`.\n\n## Reusing parameters across images\n\nMap a friendly path to the endpoint with a redirect/rewrite.\n\n`_redirects`:\n```\n/transform-small/* /.netlify/images?url=/:splat&w=50&h=50 200\n```\n\n`netlify.toml`:\n```toml\n[[redirects]]\n  from = \"/transform-small/*\"\n  to = \"/.netlify/images?url=/:splat&w=50&h=50\"\n  status = 200\n```\n\nThen `GET /transform-small/owl.jpeg` returns the transformed image. **Cross-site redirects for transformations are NOT recommended** — they can degrade site performance.\n\n## Caching headers\n\nApply custom headers to source images on the site's own domain; they carry through to the transformed output.\n\n`netlify.toml`:\n```toml\n[[headers]]\n  for = \"/source-images/*\"\n  [headers.values]\n    Cache-Control = \"public, max-age=604800, must-revalidate\"\n```\n\n- Custom headers can be applied to source images on the site's domain only — NOT to remote source images (Netlify does respect cache headers the external domain sends).\n- `Cache-Control` on source images applies only to browsers and CDNs in front of Netlify, NOT the Netlify Cache itself.\n\n## Blur placeholders (fm=blurhash)\n\n`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 (https://blurha.sh), and load the real image as a separate request without `fm=blurhash`.\n\n## Local development\n\nThe `/.netlify/images` endpoint, `[images]` allowlisting, and image redirects only exist under `netlify dev` (Netlify CLI). A local **404 on `/.netlify/images` almost always means a framework dev server (`vite`, `next dev`, `astro dev`) is running instead of `netlify dev`** — the URL itself is usually fine. Start the local environment with `netlify dev`.\n\n## User-uploaded image pipelines\n\nFor pipelines composing Functions + Blobs + Image CDN (handling user-uploaded images), see `references/user-uploads.md`.\n\n## Framework image handling\n\nMany frameworks route their built-in image optimization through Netlify Image CDN — use the framework's standard image component/syntax and only configure the remote allowlist. For unlisted frameworks, call `/.netlify/images` directly.\n\n| Framework | Prerequisites | Remote allowlist location |\n|-----------|---------------|---------------------------|\n| Angular | None; `NgOptimizedImage` uses it automatically | `[images] remote_images` in `netlify.toml` |\n| Astro | None; `<Image />` uses it automatically | `image.domains` or `image.remotePatterns` in `astro.config.mjs` |\n| Gatsby (both 5.13+ and 5.11 or earlier) | Set env `NETLIFY_IMAGE_CDN=true`; use Contentful/Drupal/WordPress source plugins | `[images] remote_images` in `netlify.toml` |\n| Next.js | Next.js 13.5+ and Next.js adapter v5 | `remotePatterns` in `next.config.js` |\n| Nuxt | None; `nuxt/image` module uses it automatically | `image.domains` in `nuxt.config.ts` |\n\nSetup guides: [Angular](https://docs.netlify.com/build/frameworks/framework-setup-guides/angular#netlify-image-cdn), [Astro](https://docs.netlify.com/build/frameworks/framework-setup-guides/astro#netlify-image-cdn), [Gatsby](https://docs.netlify.com/build/frameworks/framework-setup-guides/gatsby/#netlify-image-cdn), [Next.js](https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview), [Nuxt](https://docs.netlify.com/build/frameworks/framework-setup-guides/nuxt#netlify-image-cdn).\n\n## Additional constraints\n\n- Deploy behavior: transforms respect [atomic deploys](https://docs.netlify.com/build/caching/caching-overview#automatic-invalidation-with-atomic-deploys); changing a source image in a new deploy re-runs transforms on subsequent requests.\n- [Split Testing](https://docs.netlify.com/manage/monitoring/split-testing/) is NOT supported — image results may be inconsistent across split test branches.\n- Netlify Image CDN is NOT part of Netlify's HIPAA-compliant hosting offering.\n\nInteractive parameter playground: https://image-cdn-playground.netlify.app/\n\n<!-- system: agent-context/image-cdn/system.md — human-owned, merged by ctx-gen; edit system.md, not this section -->\n# Netlify house rules (image-cdn)\n\nThese are org conventions, not docs facts — merged into the rendered skill by\nctx-gen and never generated. Owned by the skills maintainer.\n\n1. For user-uploaded image pipelines (Functions + Blobs + Image CDN\n   composed), see `references/user-uploads.md` in this skill — an authored\n   guide with no single docs source.\n2. Percent-encode remote source URLs before placing them in the `url`\n   parameter (`encodeURIComponent`) — URLs containing `?` or `&` break\n   otherwise.\n3. `fm=blurhash` returns a BlurHash TEXT string, not image bytes. Pointing an\n   `<img src>` (or CSS background) at it renders nothing — fetch the string\n   ahead of time, decode it client-side with a BlurHash library, and load the\n   real image as a separate request without `fm=blurhash`.\n4. A local 404 on `/.netlify/images` almost always means a framework dev\n   server (`vite`, `next dev`, `astro dev`) is running instead of\n   `netlify dev` — the endpoint, `[images]` allowlisting, and image redirects\n   only exist under `netlify dev`. The URL itself is usually fine.\n5. In `remote_images` patterns, the meaningful regex escape is the dot;\n   forward slashes are not metacharacters — do not write `https:\\/\\/`.\n   In `netlify.toml`, use a single-quoted literal string\n   (`'https://example\\.com/.*'`) or double the backslash in a\n   double-quoted string (`\"https://example\\\\.com/.*\"`) — a bare `\\.`\n   inside double quotes is invalid TOML.\n"

SKILL.md line diff

--- before
+++ after
@@ -1,84 +1,180 @@
 ---
 name: netlify-image-cdn
-description: 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.
+description: Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), generating thumbnails or blur placeholders, serving remote/third-party images through the CDN, allowlisting remote domains in netlify.toml, setting up image redirects or cache headers, building user-uploaded image pipelines, or debugging a 404 on /.netlify/images. Also covers framework image handling for Angular/Astro/Gatsby/Next.js/Nuxt.
 ---
 
 # Netlify Image CDN
 
-Every Netlify site has a built-in `/.netlify/images` endpoint for on-the-fly image transformation. No configuration required for local images.
+Transform images by requesting the endpoint with a `url` query parameter. This is the current and only documented surface — there is no legacy form.
 
-## Basic Usage
+```
+GET /.netlify/images?url=<source>[&w=][&h=][&fit=][&position=][&fm=][&q=]
+```
 
-```html
-<img src="/.netlify/images?url=/photo.jpg&w=800&h=600&fit=cover&q=80" />
+```bash
+# resize a deployed image to 50px wide
+curl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&w=50'
 ```
 
-## Query Parameters
+`url` is required; all other parameters are optional.
+
+## Query parameters
+
+| Parameter | Purpose | Values | Default |
+|-----------|---------|--------|---------|
+| `url` | Source asset (required) | Relative path or remote URL | — |
+| `w` | Width in pixels | Integer | — |
+| `h` | Height in pixels | Integer | — |
+| `fit` | Resize behavior | `contain`, `cover`, `fill` | `contain` |
+| `position` | Crop anchor when `fit=cover` | `top`, `bottom`, `left`, `right`, `center` | `center` |
+| `fm` | Output format | `avif`, `jpg`, `png`, `webp`, `gif`, `blurhash` | content-negotiated |
+| `q` | Quality for lossy output | Integer `1`–`100` | `75` |
+
+## Common transformations
+
+```bash
+# resize + crop to a 50px square, retaining the left side
+curl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fit=cover&w=50&h=50&position=left'
+
+# convert JPEG to PNG (response carries content-type: image/png)
+curl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=png'
+
+# convert JPEG to AVIF at medium quality
+curl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=avif&q=50'
+```
+
+### fit behavior
+
+- **`contain` (default):** maintains aspect ratio; one dimension may come back smaller than requested. Supply one dimension and the other is computed.
+- **`cover`:** fills exactly, cropping excess. **Requires BOTH `w` and `h`** — omitting either is invalid. Use `position` to choose what's retained.
+- **`fill`:** fills exactly, stretching/squishing if aspect ratios differ.
 
-| Param | Description | Values |
-|---|---|---|
-| `url` | Source image path (required) | Relative path or absolute URL |
-| `w` | Width in pixels | Any positive integer |
-| `h` | Height in pixels | Any positive integer |
-| `fit` | Resize behavior | `contain` (default), `cover`, `fill` |
-| `position` | Crop alignment (with `cover`) | `center` (default), `top`, `bottom`, `left`, `right` |
-| `fm` | Output format | `avif`, `webp`, `jpg`, `png`, `gif`, `blurhash` |
-| `q` | Quality (lossy formats) | 1-100 (default: 75) |
+### Format notes
 
-When `fm` is omitted, Netlify auto-negotiates the best format based on browser support (preferring `webp`, then `avif`).
+- `q` applies only when output is `avif`, `jpg`, `gif`, or `webp`.
+- `webp` and `gif` can be static or animated.
+- If `fm` is omitted, format is content-negotiated from the `Accept` header: `webp` if accepted, else `avif` if accepted, else the original format. A source-only request (no other params) still converts to `webp`/`avif` but keeps size and shape.
 
-## Remote Image Allowlisting
+## Remote source images
 
-External images must be explicitly allowed in `netlify.toml`:
+Remote sources must be allowlisted in `netlify.toml` before transformation, or the request fails.
 
 ```toml
 [images]
-remote_images = ["https://example\\.com/.*", "https://cdn\\.images\\.com/.*"]
+  remote_images = ['https://my-images\.com/.*', 'https://animals.more-images.com/[bcr]at/.*']
 ```
 
-Values are regex patterns.
+Percent-encode remote source URLs before placing them in the `url` parameter with `encodeURIComponent` — a URL containing `?` or `&` breaks otherwise.
 
-## Clean URL Rewrites
+```js
+const src = `/.netlify/images?url=${encodeURIComponent('https://my-images.com/owl.jpeg?v=2')}&w=400`;
+```
 
-Create user-friendly image URLs with redirects:
+Constraints:
+- Remote sources must be **publicly accessible**.
+- Credential-bearing headers (`Authorization`, `Cookie`) are **NOT forwarded** when fetching a remote source. For authenticated sources, use URLs that carry their own authorization (e.g. S3 presigned URLs) and make sure your `remote_images` patterns match those full URLs.
 
-```toml
-# Basic optimization
-[[redirects]]
-from = "/img/*"
-to = "/.netlify/images?url=/:splat"
-status = 200
+### remote_images regex escaping
 
-# Preset: thumbnail
-[[redirects]]
-from = "/img/thumb/:key"
-to = "/.netlify/images?url=/uploads/:key&w=150&h=150&fit=cover"
-status = 200
+The only meaningful escape is the literal dot (`\.`). Forward slashes are NOT metacharacters — never write `https:\/\/`. In `netlify.toml`, use single-quoted literal strings (`'https://example\.com/.*'`) or double the backslash in double-quoted strings (`"https://example\\.com/.*"`). A bare `\.` inside double quotes is invalid TOML.
+
+## Response codes
 
-# Preset: hero
+- Invalid transformation parameter values → `404`.
+- Valid new transformation → `200` with content and matching `content-type`.
+- Previously transformed (cached) image → `304`.
+
+## Reusing parameters across images
+
+Map a friendly path to the endpoint with a redirect/rewrite.
+
+`_redirects`:
+```
+/transform-small/* /.netlify/images?url=/:splat&w=50&h=50 200
+```
+
+`netlify.toml`:
+```toml
 [[redirects]]
-from = "/img/hero/:key"
-to = "/.netlify/images?url=/uploads/:key&w=1200&h=675&fit=cover"
-status = 200
+  from = "/transform-small/*"
+  to = "/.netlify/images?url=/:splat&w=50&h=50"
+  status = 200
 ```
 
-## Caching
+Then `GET /transform-small/owl.jpeg` returns the transformed image. **Cross-site redirects for transformations are NOT recommended** — they can degrade site performance.
 
-- Transformed images are cached at the CDN edge automatically
-- Cache invalidates on new deploys
-- Set cache headers on source images to control caching:
+## Caching headers
 
+Apply custom headers to source images on the site's own domain; they carry through to the transformed output.
+
+`netlify.toml`:
 ```toml
 [[headers]]
-for = "/uploads/*"
-[headers.values]
-Cache-Control = "public, max-age=31536000, immutable"
+  for = "/source-images/*"
+  [headers.values]
+    Cache-Control = "public, max-age=604800, must-revalidate"
 ```
 
-## User-Uploaded Images
+- Custom headers can be applied to source images on the site's domain only — NOT to remote source images (Netlify does respect cache headers the external domain sends).
+- `Cache-Control` on source images applies only to browsers and CDNs in front of Netlify, NOT the Netlify Cache itself.
+
+## Blur placeholders (fm=blurhash)
+
+`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 (https://blurha.sh), and load the real image as a separate request without `fm=blurhash`.
+
+## Local development
+
+The `/.netlify/images` endpoint, `[images]` allowlisting, and image redirects only exist under `netlify dev` (Netlify CLI). A local **404 on `/.netlify/images` almost always means a framework dev server (`vite`, `next dev`, `astro dev`) is running instead of `netlify dev`** — the URL itself is usually fine. Start the local environment with `netlify dev`.
+
+## User-uploaded image pipelines
+
+For pipelines composing Functions + Blobs + Image CDN (handling user-uploaded images), see `references/user-uploads.md`.
+
+## Framework image handling
+
+Many frameworks route their built-in image optimization through Netlify Image CDN — use the framework's standard image component/syntax and only configure the remote allowlist. For unlisted frameworks, call `/.netlify/images` directly.
+
+| Framework | Prerequisites | Remote allowlist location |
+|-----------|---------------|---------------------------|
+| Angular | None; `NgOptimizedImage` uses it automatically | `[images] remote_images` in `netlify.toml` |
+| Astro | None; `<Image />` uses it automatically | `image.domains` or `image.remotePatterns` in `astro.config.mjs` |
+| Gatsby (both 5.13+ and 5.11 or earlier) | Set env `NETLIFY_IMAGE_CDN=true`; use Contentful/Drupal/WordPress source plugins | `[images] remote_images` in `netlify.toml` |
+| Next.js | Next.js 13.5+ and Next.js adapter v5 | `remotePatterns` in `next.config.js` |
+| Nuxt | None; `nuxt/image` module uses it automatically | `image.domains` in `nuxt.config.ts` |
+
+Setup guides: [Angular](https://docs.netlify.com/build/frameworks/framework-setup-guides/angular#netlify-image-cdn), [Astro](https://docs.netlify.com/build/frameworks/framework-setup-guides/astro#netlify-image-cdn), [Gatsby](https://docs.netlify.com/build/frameworks/framework-setup-guides/gatsby/#netlify-image-cdn), [Next.js](https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview), [Nuxt](https://docs.netlify.com/build/frameworks/framework-setup-guides/nuxt#netlify-image-cdn).
+
+## Additional constraints
+
+- Deploy behavior: transforms respect [atomic deploys](https://docs.netlify.com/build/caching/caching-overview#automatic-invalidation-with-atomic-deploys); changing a source image in a new deploy re-runs transforms on subsequent requests.
+- [Split Testing](https://docs.netlify.com/manage/monitoring/split-testing/) is NOT supported — image results may be inconsistent across split test branches.
+- Netlify Image CDN is NOT part of Netlify's HIPAA-compliant hosting offering.
+
+Interactive parameter playground: https://image-cdn-playground.netlify.app/
 
-Combine **Netlify Functions** (upload handler) + **Netlify Blobs** (storage) + **Image CDN** (serving/transforming) to build a complete user-uploaded image pipeline. See [references/user-uploads.md](references/user-uploads.md) for the full pattern.
+<!-- system: agent-context/image-cdn/system.md — human-owned, merged by ctx-gen; edit system.md, not this section -->
+# Netlify house rules (image-cdn)
 
-## Bundled References (Load As Needed)
+These are org conventions, not docs facts — merged into the rendered skill by
+ctx-gen and never generated. Owned by the skills maintainer.
 
-- [User uploads pipeline](references/user-uploads.md)
+1. For user-uploaded image pipelines (Functions + Blobs + Image CDN
+   composed), see `references/user-uploads.md` in this skill — an authored
+   guide with no single docs source.
+2. Percent-encode remote source URLs before placing them in the `url`
+   parameter (`encodeURIComponent`) — URLs containing `?` or `&` break
+   otherwise.
+3. `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`.
+4. A local 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.
+5. In `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.
Full snapshot data
{
  "description": "Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), generating thumbnails or blur placeholders, serving remote/third-party images through the CDN, allowlisting remote domains in netlify.toml, setting up image redirects or cache headers, building user-uploaded image pipelines, or debugging a 404 on /.netlify/images. Also covers framework image handling for Angular/Astro/Gatsby/Next.js/Nuxt.",
  "included_files": [
    {
      "relative_path": "references/user-uploads.md",
      "size_in_bytes": 4815
    }
  ],
  "name": "netlify-image-cdn",
  "skill_md_contents": "---\nname: netlify-image-cdn\ndescription: Transforms images on demand via Netlify Image CDN's /.netlify/images endpoint with query parameters for resizing/cropping/format/quality. Use when adding image optimization or responsive images, converting formats (WebP/AVIF/PNG), generating thumbnails or blur placeholders, serving remote/third-party images through the CDN, allowlisting remote domains in netlify.toml, setting up image redirects or cache headers, building user-uploaded image pipelines, or debugging a 404 on /.netlify/images. Also covers framework image handling for Angular/Astro/Gatsby/Next.js/Nuxt.\n---\n\n# Netlify Image CDN\n\nTransform images by requesting the endpoint with a `url` query parameter. This is the current and only documented surface — there is no legacy form.\n\n```\nGET /.netlify/images?url=<source>[&w=][&h=][&fit=][&position=][&fm=][&q=]\n```\n\n```bash\n# resize a deployed image to 50px wide\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&w=50'\n```\n\n`url` is required; all other parameters are optional.\n\n## Query parameters\n\n| Parameter | Purpose | Values | Default |\n|-----------|---------|--------|---------|\n| `url` | Source asset (required) | Relative path or remote URL | — |\n| `w` | Width in pixels | Integer | — |\n| `h` | Height in pixels | Integer | — |\n| `fit` | Resize behavior | `contain`, `cover`, `fill` | `contain` |\n| `position` | Crop anchor when `fit=cover` | `top`, `bottom`, `left`, `right`, `center` | `center` |\n| `fm` | Output format | `avif`, `jpg`, `png`, `webp`, `gif`, `blurhash` | content-negotiated |\n| `q` | Quality for lossy output | Integer `1`–`100` | `75` |\n\n## Common transformations\n\n```bash\n# resize + crop to a 50px square, retaining the left side\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fit=cover&w=50&h=50&position=left'\n\n# convert JPEG to PNG (response carries content-type: image/png)\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=png'\n\n# convert JPEG to AVIF at medium quality\ncurl -vs 'https://mysitename.netlify.app/.netlify/images?url=/owl.jpeg&fm=avif&q=50'\n```\n\n### fit behavior\n\n- **`contain` (default):** maintains aspect ratio; one dimension may come back smaller than requested. Supply one dimension and the other is computed.\n- **`cover`:** fills exactly, cropping excess. **Requires BOTH `w` and `h`** — omitting either is invalid. Use `position` to choose what's retained.\n- **`fill`:** fills exactly, stretching/squishing if aspect ratios differ.\n\n### Format notes\n\n- `q` applies only when output is `avif`, `jpg`, `gif`, or `webp`.\n- `webp` and `gif` can be static or animated.\n- If `fm` is omitted, format is content-negotiated from the `Accept` header: `webp` if accepted, else `avif` if accepted, else the original format. A source-only request (no other params) still converts to `webp`/`avif` but keeps size and shape.\n\n## Remote source images\n\nRemote sources must be allowlisted in `netlify.toml` before transformation, or the request fails.\n\n```toml\n[images]\n  remote_images = ['https://my-images\\.com/.*', 'https://animals.more-images.com/[bcr]at/.*']\n```\n\nPercent-encode remote source URLs before placing them in the `url` parameter with `encodeURIComponent` — a URL containing `?` or `&` breaks otherwise.\n\n```js\nconst src = `/.netlify/images?url=${encodeURIComponent('https://my-images.com/owl.jpeg?v=2')}&w=400`;\n```\n\nConstraints:\n- Remote sources must be **publicly accessible**.\n- Credential-bearing headers (`Authorization`, `Cookie`) are **NOT forwarded** when fetching a remote source. For authenticated sources, use URLs that carry their own authorization (e.g. S3 presigned URLs) and make sure your `remote_images` patterns match those full URLs.\n\n### remote_images regex escaping\n\nThe only meaningful escape is the literal dot (`\\.`). Forward slashes are NOT metacharacters — never write `https:\\/\\/`. In `netlify.toml`, use single-quoted literal strings (`'https://example\\.com/.*'`) or double the backslash in double-quoted strings (`\"https://example\\\\.com/.*\"`). A bare `\\.` inside double quotes is invalid TOML.\n\n## Response codes\n\n- Invalid transformation parameter values → `404`.\n- Valid new transformation → `200` with content and matching `content-type`.\n- Previously transformed (cached) image → `304`.\n\n## Reusing parameters across images\n\nMap a friendly path to the endpoint with a redirect/rewrite.\n\n`_redirects`:\n```\n/transform-small/* /.netlify/images?url=/:splat&w=50&h=50 200\n```\n\n`netlify.toml`:\n```toml\n[[redirects]]\n  from = \"/transform-small/*\"\n  to = \"/.netlify/images?url=/:splat&w=50&h=50\"\n  status = 200\n```\n\nThen `GET /transform-small/owl.jpeg` returns the transformed image. **Cross-site redirects for transformations are NOT recommended** — they can degrade site performance.\n\n## Caching headers\n\nApply custom headers to source images on the site's own domain; they carry through to the transformed output.\n\n`netlify.toml`:\n```toml\n[[headers]]\n  for = \"/source-images/*\"\n  [headers.values]\n    Cache-Control = \"public, max-age=604800, must-revalidate\"\n```\n\n- Custom headers can be applied to source images on the site's domain only — NOT to remote source images (Netlify does respect cache headers the external domain sends).\n- `Cache-Control` on source images applies only to browsers and CDNs in front of Netlify, NOT the Netlify Cache itself.\n\n## Blur placeholders (fm=blurhash)\n\n`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 (https://blurha.sh), and load the real image as a separate request without `fm=blurhash`.\n\n## Local development\n\nThe `/.netlify/images` endpoint, `[images]` allowlisting, and image redirects only exist under `netlify dev` (Netlify CLI). A local **404 on `/.netlify/images` almost always means a framework dev server (`vite`, `next dev`, `astro dev`) is running instead of `netlify dev`** — the URL itself is usually fine. Start the local environment with `netlify dev`.\n\n## User-uploaded image pipelines\n\nFor pipelines composing Functions + Blobs + Image CDN (handling user-uploaded images), see `references/user-uploads.md`.\n\n## Framework image handling\n\nMany frameworks route their built-in image optimization through Netlify Image CDN — use the framework's standard image component/syntax and only configure the remote allowlist. For unlisted frameworks, call `/.netlify/images` directly.\n\n| Framework | Prerequisites | Remote allowlist location |\n|-----------|---------------|---------------------------|\n| Angular | None; `NgOptimizedImage` uses it automatically | `[images] remote_images` in `netlify.toml` |\n| Astro | None; `<Image />` uses it automatically | `image.domains` or `image.remotePatterns` in `astro.config.mjs` |\n| Gatsby (both 5.13+ and 5.11 or earlier) | Set env `NETLIFY_IMAGE_CDN=true`; use Contentful/Drupal/WordPress source plugins | `[images] remote_images` in `netlify.toml` |\n| Next.js | Next.js 13.5+ and Next.js adapter v5 | `remotePatterns` in `next.config.js` |\n| Nuxt | None; `nuxt/image` module uses it automatically | `image.domains` in `nuxt.config.ts` |\n\nSetup guides: [Angular](https://docs.netlify.com/build/frameworks/framework-setup-guides/angular#netlify-image-cdn), [Astro](https://docs.netlify.com/build/frameworks/framework-setup-guides/astro#netlify-image-cdn), [Gatsby](https://docs.netlify.com/build/frameworks/framework-setup-guides/gatsby/#netlify-image-cdn), [Next.js](https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview), [Nuxt](https://docs.netlify.com/build/frameworks/framework-setup-guides/nuxt#netlify-image-cdn).\n\n## Additional constraints\n\n- Deploy behavior: transforms respect [atomic deploys](https://docs.netlify.com/build/caching/caching-overview#automatic-invalidation-with-atomic-deploys); changing a source image in a new deploy re-runs transforms on subsequent requests.\n- [Split Testing](https://docs.netlify.com/manage/monitoring/split-testing/) is NOT supported — image results may be inconsistent across split test branches.\n- Netlify Image CDN is NOT part of Netlify's HIPAA-compliant hosting offering.\n\nInteractive parameter playground: https://image-cdn-playground.netlify.app/\n\n<!-- system: agent-context/image-cdn/system.md — human-owned, merged by ctx-gen; edit system.md, not this section -->\n# Netlify house rules (image-cdn)\n\nThese are org conventions, not docs facts — merged into the rendered skill by\nctx-gen and never generated. Owned by the skills maintainer.\n\n1. For user-uploaded image pipelines (Functions + Blobs + Image CDN\n   composed), see `references/user-uploads.md` in this skill — an authored\n   guide with no single docs source.\n2. Percent-encode remote source URLs before placing them in the `url`\n   parameter (`encodeURIComponent`) — URLs containing `?` or `&` break\n   otherwise.\n3. `fm=blurhash` returns a BlurHash TEXT string, not image bytes. Pointing an\n   `<img src>` (or CSS background) at it renders nothing — fetch the string\n   ahead of time, decode it client-side with a BlurHash library, and load the\n   real image as a separate request without `fm=blurhash`.\n4. A local 404 on `/.netlify/images` almost always means a framework dev\n   server (`vite`, `next dev`, `astro dev`) is running instead of\n   `netlify dev` — the endpoint, `[images]` allowlisting, and image redirects\n   only exist under `netlify dev`. The URL itself is usually fine.\n5. In `remote_images` patterns, the meaningful regex escape is the dot;\n   forward slashes are not metacharacters — do not write `https:\\/\\/`.\n   In `netlify.toml`, use a single-quoted literal string\n   (`'https://example\\.com/.*'`) or double the backslash in a\n   double-quoted string (`\"https://example\\\\.com/.*\"`) — a bare `\\.`\n   inside double quotes is invalid TOML.\n"
}

SHA-256 of public snapshot: b941d157304b2bf090425fd7e36781833db23bb1bb0e49447839dd177363d058