# How it works

URL: /docs/plugins/payload-icons/how-it-works

How an icon name resolves through the active set, when cache entries refresh, and how to seed icons and sets declaratively.

An `<Icon name>` resolves through whichever icon set is currently **active and published**. This page traces that lookup, explains when a rendered icon refreshes after an edit, and shows how to seed icons and sets from source files.

## Resolving an icon

`<Icon name="arrow-right" />` looks the name up in the **active, published** `iconSet`. It finds the `icon` doc that row points at and inlines that doc's stored `svgString` as a real `<svg>`. The result recolors through `currentColor` and takes its size from your own classes.

The lookup reads through `payload.find` inside a `'use cache'` entry that tags itself `payload-icons`. One query resolves the whole active set, and it's reused across requests until something busts the tag — so a page of fifty icons costs one read, and usually none.

The name it matches is the *set entry's* name, not the uploaded filename. That is why swapping the active set re-skins every icon at once.

A name the active set doesn't cover renders the fallback warning glyph instead of nothing. The miss is recorded for the [Requested icons](/docs/plugins/payload-icons/collections#icon-use-detection) panel.

## Revalidation

The active-set read is a `'use cache'` entry that tags itself `payload-icons`. That's what lets a
page full of icons prerender: the SVGs come from a cache entry, not from a database read Next would
have to render around.

Install [`@pro-laico/payload-revalidate`](/docs/plugins/payload-revalidate) and the whole surface becomes self-healing, zero config. Two decoupled halves meet on that one shared tag:

- **Write side** — the `icon` and `iconSet` collections ship a data-only `custom.revalidate` marker carrying `extraTags: ['payload-icons']`. revalidatePlugin's auto-attached hooks bust that tag on every published icon/set write and delete. The after-seed flush busts it too.
- **Read side** — `getIconSvg` (and therefore `<Icon>`) calls `cacheTag` inside its own cached read. Re-upload an SVG, remap a name, or activate a different set, and every page that inlined an icon re-materializes on the next request.

Draft follows the same lane convention as the rest of the repo: a `draft` read claims both
`payload-icons` and `payload-icons:draft`, a published read claims only the plain tag. Editing a
draft never disturbs what visitors are served; publishing refreshes both.

> `iconRequest` ships `custom: { revalidate: false }` — a diagnostic feed that busts nothing.

Without the revalidate plugin nothing busts the tag, and the entry lives out its cache lifetime — the same deal any other cached read gets.

The single coarse tag is deliberate. The active-set read isn't keyed by a doc id, icon writes are rare, and the whole set resolves in a single query. See it wired end-to-end in [`examples/icons-sandbox`](https://github.com/pro-laico/payload-plugins/tree/main/examples/icons-sandbox) — which installs both plugins for exactly this reason — and in [`examples/revalidate-sandbox`](https://github.com/pro-laico/payload-plugins/tree/main/examples/revalidate-sandbox).

> Without the revalidate plugin nothing busts `payload-icons`. The read still caches, so a page that
> prerendered an icon keeps serving it until the entry expires — an SVG re-upload or an active-set
> swap won't show. Install the pair, or bust the tag yourself.

## Seeding

Because `icon` is a standard upload collection, it seeds **natively** — no script, and (unlike `payload-mux`) no `custom.seedAsset` marker. Seed it like any other collection with `defineSeed`. Each record carries its source SVG on the `_file` meta-key via the `file()` token.

Drop your source `.svg` files in the collection's folder under the seed assets dir. The folder is named after the slug, so `assets/icon/star.svg` resolves from `file('star.svg')`:

```ts
// src/seed/icons.ts — each icon doc carries its SVG on `_file`
import { defineSeed } from '@pro-laico/payload-seed'

export default defineSeed('icon', ({ file }) => [
  {
    _key: 'star',
    _file: file('star.svg'), // assets/icon/star.svg
  },
  {
    _key: 'check',
    _file: file('check.svg'), // assets/icon/check.svg
  },
])
```

Each doc is optimized on upload via the same `formatSVGHook`. An uploaded icon doesn't render on its own, though. The frontend resolves `<Icon name>` through the **active** set, so seed an `iconSet` that maps lookup names to those icons with ordinary `ref('icon', …)` tokens:

```ts
// src/seed/iconSets.ts — an active, published set wiring names to the seeded icons
import { defineSeed } from '@pro-laico/payload-seed'

export default defineSeed('iconSet', ({ ref }) => [
  {
    _key: 'default',
    title: 'Default',
    active: true,         // the live set
    _status: 'published', // visible to the non-draft frontend
    iconsArray: [
      { name: 'star', icon: ref('icon', 'star') },
      { name: 'check', icon: ref('icon', 'check') },
    ],
  },
])
```

Icons are equally referenceable from any other doc — e.g. a page's icon relationship:

```ts
// src/seed/pages.ts
import { defineSeed } from '@pro-laico/payload-seed'

export default defineSeed('pages', ({ ref }) => [
  {
    _key: 'home',
    title: 'Home',
    icon: ref('icon', 'star'),
  },
])
```

Wire the definitions into the seed plugin as usual — icons precede the set and page that reference them:

```ts
import { iconsPlugin } from '@pro-laico/payload-icons'
import { seedPlugin } from '@pro-laico/payload-seed'
import icons from './seed/icons'
import iconSets from './seed/iconSets'
import pages from './seed/pages'

plugins: [iconsPlugin(), seedPlugin({ definitions: [icons, iconSets, pages] })]
```

Because `icon` is a real collection, its seed records are type-checked and other docs reference them with `ref()`. This package never imports the seed package, so the two stay decoupled. `active: true` makes the set live and `_status: 'published'` makes it visible to the published frontend.

See the [`examples/icons-sandbox`](https://github.com/pro-laico/payload-plugins/tree/main/examples/icons-sandbox) app for a full working setup, or the [seed plugin docs](/docs/plugins/payload-seed) for the full reference.
