Reference
Plugin options, environment variables, the CLI scan command, and every export payload-icons ships.
Plugin options
iconsPlugin(options?) is the single entry point. One call registers the icon collection (upload
pipeline, on-save optimizer), the iconSet grouping collection, and the iconRequest diagnostics
collection. It's zero-config: everything is on by default.
Every collection the plugin registers is one key under collections, and each key is the uniform
{ slug?, overrides?, options? } shape: slug renames it, overrides is a Partial<CollectionConfig>
Payload passthrough, and options is this plugin's own knobs for that collection. A collection the
plugin can work without also takes false to skip it.
How an override merges
collections.<name>.overrides is a Partial<CollectionConfig> — what Payload has, you can
override. There's no allowlist of permitted keys (slug is its own key alongside overrides, not
inside it):
| Key | Merge |
|---|---|
slug (own key) | Renamed. The plugin threads the new slug everywhere it's referenced — the set's upload field, the marker, the clear-requests endpoint. |
overrides.fields | Appended after the plugin's. A duplicate name is a boot error naming the plugin, collection, and field, not a bare DuplicateFieldName. |
overrides.hooks | Merged per phase — yours run after the plugin's, so a beforeChange on icon sees the already-optimized SVG. |
overrides.access / admin / upload / custom | Shallow-merged, so you replace one key without losing the rest (admin: { group: 'Branding' } keeps useAsTitle). |
overrides.defaultPopulate / forceSelect | Merged as selects. |
everything else in overrides | Replaced — labels, versions, defaultSort, timestamps, endpoints, … |
Pass options to customize. The Reference tab is the interactive view; TypeScript is the same shape in code, every defaulted option written out.
enabledbooleandefault trueWhen false, the plugin is a no-op; no collections are registered.
collections{ icon?, iconSet?, iconRequest? }default {}
The collections the plugin registers, one key each.
iconCollectionOptiondefault {}
The icon upload collection — always registered, so no false and no plugin options.
slugstringdefault 'icon'Rename it; the icon set's upload field and the plugin marker re-point automatically.
overridesPartial<CollectionConfig>Payload config merged onto the plugin's by the shared merge rules. Rename with the sibling slug key, not here.
iconSetfalse | CollectionOption<IconSetOptions>default {}
false skips the iconSet collection entirely (only icon is registered) — use it when you want icons in the CMS but not the grouping/active-set concept.
slugstringdefault 'iconSet'Rename it; the plugin follows it.
overridesPartial<CollectionConfig>Payload config merged onto the plugin's by the shared merge rules — re-group it, wire live preview through admin.preview / admin.livePreview, turn versions off, add fields. Rename with the sibling slug key, not here.
optionsIconSetOptions
This collection's own knobs.
usagePanelbooleandefault trueThe IconSet "Requested icons" panel: shows which icons your code needs vs what a set provides (scanned live in dev, from the manifest in prod, plus runtime misses). Set false to omit it.
iconRowFieldsField[]default []Extra fields appended to every row of the icon set's iconsArray, after the built-in name and icon upload — an alias list, a per-icon note. An iconSet.overrides.fields override can't reach inside the array, which is why this is its own option under the iconSet's options.
iconRequestfalse | CollectionOptiondefault {}
false skips the iconRequest diagnostics collection and its clear endpoint — nothing tracks missing icons. Otherwise <Icon> records every name that fails to resolve at runtime (throttled, fire-and-forget), including dynamic names a static scan can't see, surfaced in the usage panel. No plugin options. To force-off only the recorder at runtime, leave the collection registered and set ICON_USAGE_TRACKING=false.
slugstringdefault 'iconRequest'Rename it; the clear endpoint follows it.
overridesPartial<CollectionConfig>Payload config merged onto the plugin's by the shared merge rules. Rename with the sibling slug key, not here.
optionsIconsOptionsdefault {}
The plugin's own knobs.
accessIconsAccessOptions
Per-endpoint gates for the plugin's HTTP endpoints — one EndpointAccess ((req) => boolean | Promise<boolean>) per endpoint. See Gating endpoints.
clearRequestsEndpointAccessdefault any logged-in userGates DELETE /payload-icons/icon-requests (the usage panel's Clear button). Only registered while the iconRequest collection is on.
import { iconsPlugin } from '@pro-laico/payload-icons'
// Defaulted options written out. This is what `iconsPlugin()` does with no args.
iconsPlugin({
enabled: true,
// one key per registered collection, each `{ slug?, overrides?, options? }`; `false` skips a collection
collections: {
// the icon upload collection — always registered, so no `false`, and no plugin `options`:
icon: {
// slug: 'glyph', // renamed everywhere the plugin refers to it
overrides: {
// labels: { singular: 'Glyph', plural: 'Glyphs' }, // replaced
// admin: { group: 'Branding' }, // shallow-merged onto the plugin's admin
// access: { read: () => true }, // shallow-merged onto the plugin's access
// fields: [{ name: 'note', type: 'text' }], // appended after the built-ins
// hooks: { beforeChange: [mine] }, // merged per phase; yours run last
},
},
// the iconSet collection; `false` omits it:
iconSet: {
overrides: {
// versions: false, // drafts are on by default
// fields: [{ name: 'description', type: 'textarea' }],
// admin: { livePreview: { url: ({ data }) => `${process.env.SITE_URL}/preview/${data.id}` } },
},
options: {
usagePanel: true, // the "Requested icons" panel; set false to omit
iconRowFields: [], // e.g. [{ name: 'aliases', type: 'text', hasMany: true }]
},
},
// the iconRequest diagnostics collection; `false` omits it (no runtime miss tracking):
iconRequest: {},
},
options: {
access: {
// clearRequests: ({ user }) => Boolean(user), // default: any logged-in user
},
},
})Environment variables
Two env vars tune usage detection at runtime, independent of the plugin options.
Prop
Type
CLI commands
| Command | What |
|---|---|
payload-icons-scan | Scan source for <Icon name> and write the usage manifest (icon-usage-manifest.json). Run it in your production build so the Requested icons panel works where source isn't on disk. Scans ./src and ./app; -o sets the manifest path, --component Glyph scans a different component. See Collections. |
Endpoints
| Method & path | What |
|---|---|
DELETE /api/payload-icons/icon-requests | Clears every iconRequest doc — the action behind the usage panel's Clear button. Gated by options.access.clearRequests (any logged-in user by default; see Gating endpoints). The gate is the outer door only — the delete runs as the caller (overrideAccess: false), so the iconRequest collection's own delete access still applies and a caller the gate admits can still clear nothing. Registered only while the iconRequest collection is on; the path is fixed (a renamed iconRequest slug changes the delete target, not the route). |
Icon-set activation itself happens in the admin, or through the companion
@pro-laico/payload-dev-tools /dev panel.
Exports
| Export | From | What |
|---|---|---|
iconsPlugin | @pro-laico/payload-icons | The plugin factory and single entry point (also the default export). |
IconsPluginOptions | @pro-laico/payload-icons | The iconsPlugin(options?) argument type: { enabled?, collections?, options? }. |
IconsCollectionsOptions | @pro-laico/payload-icons | The collections shape: { icon?, iconSet?, iconRequest? }. |
IconSetOptions | @pro-laico/payload-icons | The iconSet collection's own knobs: { usagePanel?, iconRowFields? }. |
IconsOptions | @pro-laico/payload-icons | The root options shape: { access? }. |
IconsAccessOptions | @pro-laico/payload-icons | The options.access gate-map shape: { clearRequests? }. |
EndpointAccess | @pro-laico/payload-icons | The endpoint-gate function type (req) => boolean | Promise<boolean>; see Gating endpoints. |
IconDoc | @pro-laico/payload-icons | The icon document type: { id, filename?, svgString?, optimized? }. |
readIconsMarker | @pro-laico/payload-icons | The typed view of config.custom.payloadIcons: { options, iconSlug, iconSetSlug, iconRequestSlug }. The supported way to discover the slugs the plugin registered — they follow collections.<name>.slug, and iconSetSlug / iconRequestSlug are null when that collection is off. Returns undefined when the plugin isn't registered. |
PayloadIconsMarker | @pro-laico/payload-icons | The marker's type. |
extractSvgContent | @pro-laico/payload-icons | Pull the inner markup out of an svgString to inline it in your own <svg>. |
extractSvgProps | @pro-laico/payload-icons | Parse an svgString's root attributes (viewBox, etc.) onto your own <svg>. |
createIcon | @pro-laico/payload-icons/components/Icon | Factory that takes a Payload handle and returns the <Icon name="…" /> server component — const Icon = createIcon(getPayload({ config })) (resolves through the active set). Props: name, optional fallback and draft, plus any SVG attribute. |
getIconSvg | @pro-laico/payload-icons/cache | Resolve one icon name to its svgString through the active set (server-only; one cached, tagged read serves the whole set). |
payload-icons-scan | bin | CLI that scans source for <Icon name> and writes the usage manifest. |
Collections & globals
iconsPlugin() registers the icon, iconSet, and iconRequest collections — see
Collections for their fields, hooks, and the icon-use
detection panel.
How it works
How an icon name resolves through the active set, when cache entries refresh, and how to seed icons and sets declaratively.
Troubleshooting
Fix a fallback glyph, a solid-blob icon, a blank admin preview, or an empty requested-icons panel — symptom-first, with the exact strings to search for.