Sometimes icons come from more than one source. The chain provider wraps multiple providers in priority order and returns the first match, so local overrides take precedence over remote fallbacks.
What it does
ChainProvider wraps an ordered list of providers and returns the first match. It lets multiple icon sources act as a single provider with fallback behavior.
When to use it
Reach for a chain when the project needs local overrides on top of a remote source, or when combining multiple icon sets under a single prefix. The most common pattern is a directory of custom SVGs backed by the Iconify API for everything else.
For single-source providers, see Directory Provider, JSON Collection Provider, or Iconify Provider.
Setup
Direct construction
import swarmicons "github.com/frostybee/go-swarm-icons"dirP, err := swarmicons.NewDirectoryProvider("./heroicons")if err != nil { log.Fatal(err)}iconifyP := swarmicons.NewIconifyProvider("heroicons")chain := swarmicons.NewChainProvider(dirP, iconifyP)manager := swarmicons.Default("heroicons", chain)The directory provider is checked first. If it has the icon, the Iconify provider is never called.
Config builder with AddHybridSet
The AddHybridSet shortcut creates a ChainProvider combining a DirectoryProvider and an IconifyProvider under a single prefix:
import swarmicons "github.com/frostybee/go-swarm-icons"manager, err := swarmicons.NewConfig(). AddHybridSet("heroicons", "./heroicons"). DefaultPrefix("heroicons"). Build()This is equivalent to the manual chain above, but constructed internally during Build().
Options & behavior
Resolution order
Get() iterates the provider list in order and returns the first icon found. If no provider has the icon, it returns (nil, false).
Chain[DirectoryProvider, IconifyProvider]Get("home"): 1. DirectoryProvider.Get("home") → found? return it 2. IconifyProvider.Get("home") → found? return it 3. not found → (nil, false)Has() short-circuits
Has() returns true as soon as any provider in the chain reports the icon exists. It does not query remaining providers.
All() deduplicates
All() returns the union of all providers' icon names, deduplicated. Names appear in the order they are first encountered (first provider's names first, then new names from subsequent providers).
No internal caching
The chain provider does not cache results itself. Each wrapped provider manages its own cache. Repeated Get() calls on the chain still benefit from each provider's internal caching.
Constructor
NewChainProvider copies the provider slice. Modifying the original slice after construction has no effect on the chain.
Examples
Local overrides with remote fallback
import ( "fmt" "log" swarmicons "github.com/frostybee/go-swarm-icons")func main() { // Local directory with a few custom overrides dirP, err := swarmicons.NewDirectoryProvider("./overrides/heroicons") if err != nil { log.Fatal(err) } // Iconify API as the fallback for icons not in the directory iconifyP := swarmicons.NewIconifyProvider("heroicons") chain := swarmicons.NewChainProvider(dirP, iconifyP) manager := swarmicons.Default("heroicons", chain) // "home" resolves from disk if ./overrides/heroicons/home.svg exists, // otherwise from the Iconify API. icon, err := manager.Get("home") if err != nil { log.Fatal(err) } fmt.Println(icon.ToHTML())}Config builder shortcut
import ( "fmt" "log" swarmicons "github.com/frostybee/go-swarm-icons" "github.com/frostybee/go-swarm-icons/lucide")func main() { manager, err := swarmicons.NewConfig(). AddProvider("lucide", lucide.Provider()). AddHybridSet("heroicons", "./heroicons"). DefaultPrefix("lucide"). Build() if err != nil { log.Fatal(err) } // Lucide icon via default prefix home, _ := manager.Get("home") fmt.Println(home.ToHTML()) // Heroicons via explicit prefix (directory checked first, then Iconify) check, _ := manager.Get("heroicons:check-circle") fmt.Println(check.ToHTML())}Choosing a provider
| Provider | Source | Network | Disk | Caching | Best for |
|---|---|---|---|---|---|
| Directory | .svg files |
No | Yes | Per-icon on first access | Custom/brand icons |
| JSON Collection | Iconify JSON | No | Yes (or go:embed) |
Full parse on first call | Production icon sets |
| Iconify API | HTTP API | Yes | No | Per-icon on first fetch | Prototyping, unknown sets |
| Chain | Multiple providers | Depends | Depends | Per-provider | Local-first + fallback |
| Embedded Lucide | go:embed in binary |
No | No | Full parse on first call | Quick start, Lucide-only |
See also
- Providers API reference: full
ChainProviderconstructor and resolution semantics - Directory Provider: the most common first provider in a chain
- Iconify Provider: the most common fallback provider in a chain