An aggregated, enriched catalog of open-source icons with a free public search API and a web app. Built for developers and AI agents.
Live: icons.grida.co · API: /llms.txt · API reference
Grida Icons mirrors several popular open-source icon sets as git submodules,
runs them through a Python pipeline that normalizes the SVGs and attaches a
uniform text layer (a one-line description + searchable tags for every
icon), and serves the result through a Next.js web app and a zero-auth REST API.
Six upstream sets, ~5,000 logical icons and logos (many more when you count per-style/weight variants). Exact, build-generated counts live in dist/stats.json — the badges above read from it, and every dist rebuild (including the weekly refresh PR) regenerates it. Sources are tracked as submodules under vendor/; the published catalog lives in dist/.
| Set | id | Source |
|---|---|---|
| Heroicons | heroicons |
tailwindlabs/heroicons |
| Lucide | lucide-icons |
lucide-icons/lucide |
| Phosphor | phosphor-icons |
phosphor-icons/core |
| Octicons | octicons |
primer/octicons |
| Radix UI | radix-ui-icons |
radix-ui/icons |
| SVGL (brand logos) | svgl |
pheralb/svgl |
Each set keeps its upstream license — see dist/<set>/LICENSE (aggregated in the root LICENSE). Review the source project before redistribution.
A free, public, zero-auth REST API. No API key, open CORS, edge-cached. Base URL https://icons.grida.co.
# keyword search (ranked over name + tags; one result per logical icon)
curl "https://icons.grida.co/api/search?q=trash&limit=2"GET /api/search?q=&vendor=&limit=&offset=— ranked keyword search (recommended).GET /api— every icon file (one item per variant); filter byvendor,q,variant:<key>=<value>.GET /api/logos— brand logos (SVGL).GET /api/vendors— per-set metadata (id, name, version, count, variant axes).GET /dist/{vendor}/{file}— the raw SVG, immutable-cached and safe to hotlink.
Full contract: /docs and /llms.txt.
vendor/ upstream icon sources (git submodules)
pipeline/ Python (uv) tooling: builds dist/ and enriches per-icon text metadata
dist/ published catalog — dist/<set>/{data.json, src/*.svg, LICENSE}
www/ Next.js web app: search UI, public API, docs
sets/ legacy pre-pipeline data-wrangling experiments (not part of the build)
dist/<set>/data.json carries package metadata plus a files[] list, each entry
{ name, file, properties, description, tags } — description/tags are the
enriched text layer; properties holds per-variant axes (e.g. style, weight).
Clone with submodules (the vendor sources live there):
git clone --recurse-submodules https://github.com/gridaco/icons
# already cloned?
git submodule update --init --recursiveThe repo is a pnpm root pinned to Node 24 (.nvmrc) and pnpm 11.5.1.
Formatting and linting use the oxc toolchain — oxfmt and oxlint, no
ESLint/Prettier — wired into a lefthook pre-commit hook.
pnpm install # installs the lefthook git hook via `prepare`
pnpm fmt # format with oxfmt (fmt:check to verify only)
pnpm lint # lint with oxlintNext.js 16 (App Router, Turbopack), React 19, Tailwind v4, MiniSearch.
pnpm --dir www dev # dev server on http://localhost:3000
pnpm --dir www build # production build
pnpm --dir www typecheck # tsc --noEmit
pnpm --dir www lint # oxlintBoth the client and server search read a prebuilt index from
www/scripts/build-search-index.mjs (run automatically in predev/prebuild).
Its output (www/public/search-index.json) and the copied www/public/dist are
generated and git-ignored.
Python 3.12+ managed with uv. Builds dist/ from
the vendor submodules and enriches the per-icon text layer. See
pipeline/README.md for the full reference.
cd pipeline
uv sync
uv run main.py dist # rebuild dist/ (SVGs + per-set data.json + LICENSE)
uv run main.py validate # gate: each data.json parses and matches its SVG countEnrichment fills a uniform description + tags for every icon. Native vendor
tags (Lucide/Phosphor/Octicons) are preserved; gaps are filled by a local
ollama vision model fed the icon as a PNG — no API cost, no data leaving the
machine. It needs rsvg-convert (brew install librsvg) and a pulled vision
model. The full ~4,260-icon pass is already committed under
pipeline/enrichment/; re-run only when sets add icons
or the model/prompt changes (it's resumable).
uv run main.py enrich <set> # e.g. enrich heroicons (resumable; --force to redo)
uv run main.py enrich-validate # contract check + per-set coverage report.github/workflows/update-icons.yml runs
weekly (Mondays 06:00 UTC, or on demand via workflow_dispatch): it bumps every
vendor/* submodule to latest upstream, rebuilds dist/, runs validate plus a
regression gate (fails if any set's count drops >25%), and opens a
bot/icons-update PR. Data changes always land via that PR so a human reviews
the diff before the site serves it. No secrets required — every source is a
submodule.
Contributions welcome — new sources, better metadata, search improvements. Branch
off main; let oxfmt/oxlint handle formatting (the pre-commit hook runs
them). Don't commit generated artifacts (www/public/dist,
www/public/search-index.json). See AGENTS.md for agent-oriented
guidance.
See LICENSE. Each upstream icon set retains its own license under
dist/<set>/LICENSE.