# Reference

URL: /docs/plugins/payload-images/reference

Every plugin option, environment variable, CLI command, endpoint, and export in one place.

`imagesPlugin(options?)` is the single entry point. One call registers the collections, the
transform and purge endpoints, and the admin UI. It's zero-config — everything below is a knob you
can turn later.

## Plugin options

The shape splits along one seam: the collections the plugin registers live under `collections`, and
the render engine's knobs live under `options`. Every `collections.<name>` takes the same three keys
— `slug` renames it, `overrides` is a Payload `CollectionConfig` passthrough the merge kit applies,
and `options` (on `images`) is the plugin's own knobs for *that* collection. Optional sub-features
read `false | Options`: `options.prewarm: {}` is "on, all defaults", `options.prewarm: false` opts
out.

The **Reference** tab is the interactive view (`collections` and `options` expand to their nested
options); **TypeScript** is the same shape in code, every option at its default.

**Reference**

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | `boolean` | `true` | When false, registers nothing. This is "not installed", not "paused": on SQL adapters, turning it off for an existing project produces a migration that drops the image tables and their data. |
| `collections` | `{ images?, generatedImages?, renderProfiles? }` |  | The collections the plugin registers, one key each. Every key takes the same shape: slug renames the collection (the plugin repoints every internal reference at the new name), overrides is a Payload CollectionConfig passthrough merged onto the plugin's (upload/access/admin/custom shallow-merged, fields/hooks appended, defaultPopulate/forceSelect merged as selects — which matters on images, where the plugin sets both — everything else replaced), and images additionally takes options — its own knobs. |
| `collections.images` | `CollectionOption<ImagesCollectionOptions>` |  | The Images collection you touch. |
| `collections.images.slug` | `string` | `'images'` | Rename it; the plugin repoints every internal reference (the variant cache's source relationship, the variants join, the purge hooks, the endpoints, the marker) at the new name. |
| `collections.images.overrides` | `Partial<CollectionConfig>` |  | Payload config merged onto the plugin's by the shared merge rules. Rename with the sibling slug key, not here. Don't redeclare a base field name like alt or variants — that's a named boot error. |
| `collections.images.options` | `ImagesCollectionOptions` |  | This collection's own knobs. |
| `collections.images.options.focalUI` | `false \| { previewRatios?: string[] }` | `{}` | Render the focal-point picker + ratio-preview field and the preset manager panel (preset toggles, cached-variant list, purge button, per-image variant cap). The object form customizes the aspect ratios shown as preview tiles (default ['16:9','9:16','1:1','4:3','3:2','21:9']). false leaves a clean upload collection, and the import map isn't needed. |
| `collections.images.options.folders` | `boolean` | `true` | Payload's native folder organization on the images collection, so editors can organize a large library. On by default — a managed image library without organization is the wrong default. It adds a nullable folder relationship and Payload's hidden payload-folders collection: additive, so an existing database needs a schema push but no data migration. Set false to opt out. |
| `collections.images.options.localizeAlt` | `boolean` | `whether the app configures localization` | Mark the alt field localized (requires Payload localization). Defaults to Boolean(config.localization) — a localized site localizes its alt text, an accessibility fact rather than a preference. Flipping it on an existing collection is a data migration, so set it explicitly to opt out. |
| `collections.images.options.mimeTypes` | `string[]` | `['image/avif','image/webp','image/jpeg','image/png']` | Accepted upload mime types for the images collection; defaults to the raster formats the transform pipeline can process. Widen it (e.g. add 'image/svg+xml') or narrow it, but the endpoint only meaningfully resizes/crops raster images; non-raster uploads are stored and served as-is. |
| `collections.images.options.maxOriginalSize` | `number` |  | Cap the stored original's longest edge (px), applied once on upload. Off by default; your original stays untouched (the collection can double as original storage). Set it only to bound storage. |
| `collections.generatedImages` | `CollectionOption` |  | The hidden generated-images (variant cache) collection. No plugin options. |
| `collections.generatedImages.slug` | `string` | `'generated-images'` | Rename it; the variants join, admin panel, and marker follow. |
| `collections.generatedImages.overrides` | `Partial<CollectionConfig>` |  | Payload config merged onto the plugin's by the shared merge rules. Rename with the sibling slug key, not here. |
| `collections.renderProfiles` | `CollectionOption` |  | The image-render-profiles collection that prewarming records its observations in. Only registered while options.prewarm is on — prewarm governs whether the collection exists, this key only shapes it. No plugin options. |
| `collections.renderProfiles.slug` | `string` | `'image-render-profiles'` | Rename it; the recorder, the prewarm task, and the marker follow. |
| `collections.renderProfiles.overrides` | `Partial<CollectionConfig>` |  | Payload config merged onto the plugin's by the shared merge rules. Rename with the sibling slug key, not here. |
| `options` | `ImagesOptions` |  | The render engine — the on-demand transform endpoint, its prewarming, and the variant/preset ladder. |
| `options.transform` | `TransformEndpointConfig` | `{}` | Config for the on-demand transform + purge endpoints. The endpoint is always registered — it is the plugin. |
| `options.transform.cdnCacheControl` | `boolean` | `true` | Also emit CDN-Cache-Control / Vercel-CDN-Cache-Control headers (public images only). |
| `options.transform.maxDimension` | `number` | `4096` | Hard ceiling on either output dimension. |
| `options.transform.defaultQuality` | `number` | `90` | Encode quality used when a request omits q. |
| `options.transform.qualityRange` | `[number, number]` | `[40, 95]` | Allowed quality range; requested values clamp into it. |
| `options.transform.defaultFormat` | `Format` | `'auto'` | Output format when a request omits fmt (auto negotiates from Accept). |
| `options.transform.formats` | `Format[]` | `['auto','avif','webp','jpeg','png']` | Output formats the endpoint may emit. |
| `options.transform.preferAvif` | `boolean` | `false` | Auto-negotiate AVIF when accepted. Off by default: AVIF encodes far slower, so fmt=auto serves WebP for a fast cold path (AVIF stays available on explicit fmt=avif). |
| `options.transform.maxInputPixels` | `number` | `100000000` | Max source pixels Sharp will decode: a decompression-bomb guard that also caps per-transform memory (~100MP ≈ 400MB). |
| `options.transform.maxConcurrency` | `number` | `cpus - 1 (computed)` | Max concurrent Sharp transforms in this process (or IMAGES_TRANSFORM_CONCURRENCY). Computed from the host CPU count. |
| `options.transform.sharpConcurrency` | `number` | `1` | Per-image libvips thread cap (or IMAGES_SHARP_CONCURRENCY); 0 = CPU cores. Defaults to 1 for serverless safety. |
| `options.transform.fallback` | `boolean` | `true` | On a cache miss with a NEARBY variant ready — same fit and focal point, ratio within 8% drift, at least half the effective request width, any quality, in a format the client's negotiation proved it decodes — serve it immediately with Cache-Control: no-store while the exact variant generates in the background. The next request gets the exact one; the stand-in is never cached or persisted. |
| `options.prewarm` | `false \| PrewarmOptions` | `{}` | Smart prewarming, driven by a strategy: warm the built-in renders, seeds (default: a square 1:1 q80 crop at the derived widths — declaring your own replaces it), and learned traffic profiles for new/replaced/re-focused images via a deferred Payload Job. On by default (a cold variant is a visible LCP hit on image-led pages); the object form takes strategy / formats / maxVariantsPerImage — the strategy carries widths ('srcset', { every: n }, or a list), builtIns, learned, seeds, onUpload, autoRun, autoRunLimit, and queue — and prewarm: false opts out entirely. Being on registers the hidden image-render-profiles collection (a schema change — regenerate types), the imagesPrewarm jobs task, the images:prewarm CLI, and by default the autoRun runners on the plugin-owned images-prewarm queue: a 5-minute cron (50 jobs per firing) on long-lived processes, plus a post-upload kick and an image-traffic drain that keep jobs running on serverless too — see Prewarming → When it runs. |
| `options.pixelStep` | `number \| number[]` | `50` | Project-wide srcset widths and the endpoint's snap grid. The default 50 steps srcset densely (every 50px up to the source width) and snaps freeform requests to the same grid — prewarm warms an every-5th skeleton and the fallback bridges the rest. An array switches srcset to a fixed breakpoint ladder (e.g. next/image's deviceSizes [640, 750, 828, 1080, 1200, 1920, 2048, 3840]) whose widths always pass the snap unchanged — smaller responses on wide originals, and prewarm warms the ladder exactly. maxDimension caps the top. |
| `options.presetTemplates` | `Record<string, PresetSpec>` | `{ og, thumbnail }` | Named, reusable variant specs ({ width?, height?, aspectRatio?, fit?, quality?, format? }) that editors toggle onto images by name and serve via /api/img/:id?preset=<name>. Guaranteed (cap-exempt) and eagerly pre-generated on upload. Two defaults ship unless overridden: og (1200×630 cover jpeg, q80) and thumbnail (160×160 cover webp, q70 — backs the admin thumbnail). See Caching → Guaranteed presets. |
| `options.variantLimit` | `number` | `200` | Per-image cap on cached variants — bounds storage from the public endpoint. Each image gets a variantLimit field defaulting to this; past the cap a new freeform size is served from a nearby variant (or generated but not stored) instead of adding a row. Presets are exempt. See Caching → The variant cap. |
| `options.access` | `ImagesAccessOptions` |  | Per-endpoint gates for the plugin's HTTP endpoints — one EndpointAccess ((req) => boolean \| Promise<boolean>) per endpoint. The source doc's own read access is still enforced on top of both. See Gating endpoints. |
| `options.access.manage` | `EndpointAccess` | `any logged-in user` | Gates the per-source admin endpoints (/img/purge/:id, /img/presets/:id, /img/prewarm/:id). |
| `options.access.serve` | `EndpointAccess` | `public` | Gates the transform/serve endpoint (GET /img/:id). Public by default — image serving must answer anonymous traffic; the source collection's read access still applies. |

**TypeScript**

```ts
import { imagesPlugin } from '@pro-laico/payload-images'

// Every option at its default. This is the zero-config behaviour, written out.
imagesPlugin({
  enabled: true,
  collections: {
    images: {
      // slug: 'media',              // optional, no default: renames the collection (references follow)
      // overrides: { /* … */ },     // optional, no default: a Payload CollectionConfig merged onto it
      options: {
        focalUI: {}, // or { previewRatios: ['16:9', '9:16', '1:1', '4:3', '3:2', '21:9'] }
        folders: true,
        // localizeAlt: false,       // default: whether your config sets `localization`
        mimeTypes: ['image/avif', 'image/webp', 'image/jpeg', 'image/png'],
        // maxOriginalSize: 4096,    // optional, no default: off (the original is kept untouched)
      },
    },
    // generatedImages: { slug: 'variant-cache' }, // optional: rename / override the variant cache
    // renderProfiles: { slug: 'render-shapes' },   // optional: rename / override the prewarm registry
  },
  options: {
    transform: {
      cdnCacheControl: true,
      maxDimension: 4096,
      defaultQuality: 90,
      qualityRange: [40, 95],
      defaultFormat: 'auto',
      formats: ['auto', 'avif', 'webp', 'jpeg', 'png'],
      preferAvif: false,
      maxInputPixels: 100_000_000,
      // maxConcurrency: cpus - 1,  // default (computed from host CPUs, or IMAGES_TRANSFORM_CONCURRENCY)
      sharpConcurrency: 1,
      fallback: true,
    },
    prewarm: {
      // or false to opt out; `strategy: 'default'` ≡ `strategy: {}` ≡ this, written out:
      strategy: {
        widths: { every: 5 }, // the numeric-grid default — 'srcset' with an array pixelStep, or an explicit number[]
        builtIns: true,   // warm src / thumbnailURL / placeholderURL
        learned: true,    // warm observed render profiles
        seeds: [{ aspectRatio: '1:1', quality: 80 }], // declaring your own replaces this default; [] disables
        onUpload: true,   // enqueue on create / file replace / focal edit
        autoRun: '*/5 * * * *', // the plugin runs its own jobs: this cron on long-lived processes, upload kicks + traffic drains on serverless — false turns all three off
        autoRunLimit: 50, // jobs (images) per cron firing / upload kick
        queue: 'images-prewarm', // plugin-owned, so the plugin's runners only ever run its own jobs
      },
      formats: ['webp'],  // +'avif' automatically when transform.preferAvif
      maxVariantsPerImage: 32,
    },
    pixelStep: 50, // the dense grid — or an array ladder, e.g. [640, 750, 828, 1080, 1200, 1920, 2048, 3840]
    presetTemplates: {
      // both ship by default; your own entries merge on top
      og: { width: 1200, height: 630, fit: 'cover', quality: 80, format: 'jpeg' },
      thumbnail: { width: 160, height: 160, fit: 'cover', quality: 70, format: 'webp' },
    },
    variantLimit: 200,
    // access: {                    // per-endpoint gates for the plugin's HTTP endpoints
    //   manage: ({ user }) => Boolean(user), // default: any logged-in user (source read still enforced)
    //   serve:  () => true,                  // default: public (source read still applies)
    // },
  },
})
```

> The named option types — `Format`, `TransformEndpointConfig`, `PresetSpec`, `PrewarmOptions`, and
> `PrewarmStrategy` — all import from `@pro-laico/payload-images`.

> **`enabled: false` means "not installed", not "paused".** On SQL adapters, turning it off for an
> existing project produces a migration that drops the image tables — including every cached
> variant.

## Environment variables

These set per-process defaults without changing code (handy for serverless). An explicit
`options.transform.*` value **wins** over the matching env var — the env var is the default when the
option is unset.

| Variable                        | Default                     | What                                                                                                                                                                                                                                       |
| ------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `IMAGES_TRANSFORM_CONCURRENCY`  | `cpus - 1` (computed)       | Max concurrent Sharp transforms in this process. The default for `transform.maxConcurrency`.                                                                                                                                               |
| `IMAGES_TRANSFORM_MAX_QUEUE`    | `max(64, concurrency × 32)` | Queued transforms allowed before the endpoint sheds load with a `503`.                                                                                                                                                                     |
| `IMAGES_SHARP_CONCURRENCY`      | `1`                         | Per-image libvips thread cap; `0` = CPU cores. The default for `transform.sharpConcurrency`.                                                                                                                                               |
| `IMAGES_PREWARM_FLUSH_MS`       | `30000`                     | Debounce before buffered prewarm observations flush to the render-profiles collection (armed by the first observation after a flush). Newly seen widths write on flush; pure hit-count bumps persist at most every 15 minutes per profile. |
| `NEXT_PUBLIC_SERVER_URL`        | —                           | Base URL for generated image URLs.                                                                                                                                                                                                         |
| `VERCEL_PROJECT_PRODUCTION_URL` | —                           | Fallback base URL when `NEXT_PUBLIC_SERVER_URL` is unset.                                                                                                                                                                                  |

## CLI commands

The plugin registers two Payload CLI commands (run via `pnpm payload <command>`).

| Command                   | Flags                                         | What                                                                                                                                                                                                                                                      |
| ------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payload images:backfill` | `--force`, `--focal`, `--collection`          | Stamps upload-time metadata (placeholder tiers, palette, alpha flags, saliency focal point) onto images that predate the plugin. See [Metadata → Backfilling an existing library](/docs/plugins/payload-images/metadata#backfilling-an-existing-library). |
| `payload images:prewarm`  | `--now`, `--limit`, `--collection`, `--queue` | Enqueues one prewarm job per source for a runner to execute; `--now` generates inline instead, no runner needed. Requires `prewarm` on. See [Prewarming](/docs/plugins/payload-images/prewarming).                                                        |

## Endpoints

`GET /img/:id` is gated by `options.access.serve` (public by default); the per-source admin endpoints
(purge, presets, prewarm) by `options.access.manage` (any logged-in user). The source doc's own read
access is enforced on top of both. See [Gating endpoints](../conventions#gating-endpoints).

| Route                      | What                                                                                                                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /api/img/:id`         | The on-demand transform endpoint: reads the image `id` and the transform query params, renders the variant once, then caches it. See [Image URLs](/docs/plugins/payload-images/image-urls). |
| `POST /api/img/purge/:id`  | Purge this image's cached variants (the **Preset manager** panel's purge button posts here).                                                                                                |
| `GET /api/img/presets/:id` | Which presets exist for this image, each mapped to its cache key and cached variant.                                                                                                        |
| `GET /api/img/prewarm/:id` | Prewarm plan and job status (pending job, last run). Registered only while `options.prewarm` is on.                                                                                         |

## Exports

| Export                                                                                                                             | From                                            | What                                                                                                                                                                                                                                                         |
| ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `imagesPlugin`                                                                                                                     | `@pro-laico/payload-images`                     | The Payload plugin; put `imagesPlugin()` in your config's `plugins`.                                                                                                                                                                                         |
| `ResponsiveImage`                                                                                                                  | `@pro-laico/payload-images/components/image`    | The passive responsive `<img>` component.                                                                                                                                                                                                                    |
| `createImageFor`                                                                                                                   | `@pro-laico/payload-images`                     | Seed once with your Payload handle → `imageFor(id).aspectRatio('16:9').blur('md').fetch()` resolves the render-ready doc for `<ResponsiveImage>`.                                                                                                            |
| `RESPONSIVE_IMAGE_SELECT`                                                                                                          | `@pro-laico/payload-images`                     | The lean select for a render-declared read (`alt` + `src` + `aspectRatio` + `srcset` + `placeholder`) — for writing the `findByID` yourself.                                                                                                                 |
| `getImageUrl`                                                                                                                      | `@pro-laico/payload-images/utils/urls`          | Build one transform URL for an image (an id or a populated doc): OG tags, CSS backgrounds, emails.                                                                                                                                                           |
| `buildSrcset`                                                                                                                      | `@pro-laico/payload-images/utils/urls`          | Build a responsive `srcset` + default `src` for an image (an id or a populated doc — a doc also supplies the width cap and cache-busting token).                                                                                                             |
| URL-builder types                                                                                                                  | `@pro-laico/payload-images/utils/urls`          | `GetImageUrlOptions`, `ImageResource`, `BuildSrcsetOptions`, `BuildSrcsetResult`, `BuildUrlOptions`, plus `Fit` and `Format` re-exported alongside them.                                                                                                     |
| Component prop types                                                                                                               | `@pro-laico/payload-images/components/image`    | `ImageProps`, `ResponsiveImageProps` — for typing a wrapper around `<ResponsiveImage>`.                                                                                                                                                                      |
| `FocalPreview`                                                                                                                     | `@pro-laico/payload-images/admin/focalPreview`  | Admin focal-point picker + ratio/placeholder preview field (wired via the import map when `collections.images.options.focalUI` is on).                                                                                                                       |
| `PresetManager`                                                                                                                    | `@pro-laico/payload-images/admin/presetManager` | Admin **Preset manager** panel — preset toggles, cached-variant list, purge button, and the per-image variant cap (wired via the import map when `collections.images.options.focalUI` is on).                                                                |
| `PrewarmOptions` / `PrewarmStrategy` / `PrewarmStrategyConfig` / `PrewarmWidths` / `ResolvedPrewarmStrategy` / `RenderProfileSeed` | `@pro-laico/payload-images`                     | The `prewarm` option's types: the config shape, the strategy (what to warm and when it runs, with its width-axis union), and a pinned cold-start render profile.                                                                                             |
| `PresetSpec` / `PresetEntry`                                                                                                       | `@pro-laico/payload-images`                     | The presets types: a `presetTemplates` spec and a per-image `presets` array entry.                                                                                                                                                                           |
| `PREWARM_TASK_SLUG`                                                                                                                | `@pro-laico/payload-images`                     | The prewarm jobs task slug (`imagesPrewarm`) — for queueing/running the job yourself.                                                                                                                                                                        |
| `readImagesMarker`                                                                                                                 | `@pro-laico/payload-images`                     | Read the resolved config (slugs + settings) off `config.custom.payloadImages` from a script or app — `readImagesMarker(config).sourceSlug`.                                                                                                                  |
| `GENERATED_IMAGES_SLUG` / `IMAGE_RENDER_PROFILES_SLUG`                                                                             | `@pro-laico/payload-images`                     | The default slugs of the variant-cache and render-profiles collections (before any `slug` rename).                                                                                                                                                           |
| Option & marker types                                                                                                              | `@pro-laico/payload-images`                     | `ImagesPluginOptions`, `ImagesOptions`, `ImagesCollectionOptions`, `ImagesAccessOptions`, `TransformEndpointConfig`, `PayloadImagesMarker`, `PayloadImagesPrewarmMarker`.                                                                                    |
| `EndpointAccess`                                                                                                                   | `@pro-laico/payload-images`                     | The endpoint-gate function type `(req) => boolean \| Promise<boolean>`; see [Gating endpoints](../conventions#gating-endpoints).                                                                                                                             |
| Render-contract types                                                                                                              | `@pro-laico/payload-images`                     | `ImageFor`, `ImageForChain`, `ImageSource`, `ResponsiveImageDoc`, `AspectRatio`, `Fit`, `Format`, `OutputFormat`, `ImageRenderContext`, `ImageRenderIntent`, `BlurRenderIntent`, `ImagePalette`, `PaletteSwatch`, `PlaceholderFormat`, `PlaceholderQuality`. |

## Collections & globals

The plugin registers `images` (the upload collection you touch), the hidden `generated-images`
variant cache, and — with `options.prewarm` on — the hidden `image-render-profiles` registry, all
under an **Assets** admin group. `collections.images.options.folders` brings Payload's own hidden
`payload-folders` collection with it. See [Collections](/docs/plugins/payload-images/collections) for
their fields, hooks, and access.
