Rendered on the server
Each icon is a tiny <use href> into one hashed sprite. The browser fetches the sprite once and keeps it.
<Icon name="terminal" />
// <svg aria-hidden="true"><use href="/icons/icons.7ced95d4.svg#i-terminal"/></svg>v0.1 on npm · MIT · Node 22.20+
svgworm digs through your folder of SVG files and leaves one type-safe, content-hashed sprite behind. Render it from React Server Components in the Next.js App Router, and ship no icon code to the browser.
pnpm add -D svgworm && pnpm add @svgworm/react
$ pnpm svgworm
svgworm: build done
icons 19 (13 mono, 6 multicolor)
delivery use 19, img 0, mask 0
output 10.2 KiB
write public/icons/icons.7ced95d4.svg
$ pnpm tsc
error TS2322: Type '"termnial"' is not assignable to type 'IconName'.Why svgworm
Each icon is a tiny <use href> into one hashed sprite. The browser fetches the sprite once and keeps it.
<Icon name="terminal" />
// <svg aria-hidden="true"><use href="/icons/icons.7ced95d4.svg#i-terminal"/></svg>The generated types list every icon. A typo fails tsc, not production.
<Icon name="termnial" />Mono icons follow currentColor, multicolor icons keep their colors. Gradients, masks and filters render in Chromium, Firefox and WebKit.
A CLI that writes static files, byte-identical on Linux, macOS and Windows. Turbopack, webpack and Vite need no plugin, and svgworm check fails CI when the output is stale.
Get started in Next.js
init writes the config, the predev/prebuild scripts and the component.
pnpm add -D svgworm
pnpm add @svgworm/react
pnpm svgworm initEach run writes a hashed sprite to public/icons/ and a typed manifest to svgworm/.
icons/
├── home.svg
├── search.svg
└── brand/logo.svgDecorative by default. Pass title or label for an accessible name.
import { Icon } from '@/components/icon';
<Icon name="home" title="Go home" />Caching, basePath and manual setup are in the Next.js guide. A complete app lives in examples/next-app-router.
This page is the demo
/icons/icons.7ced95d4.svg, rendered by the generated Icon.astro at build time and served with Cache-Control: immutable. Open your network panel: no JavaScript, one SVG.
emoji/carrotemoji/mushroomemoji/rockemoji/seedlingemoji/snailemoji/wormarrow-rightbook-opencheckfile-codefolder-opengaugegit-branchlayerspackageservershield-checkterminalzapSame sprite, same <use href>, decided per icon. Change the text color: the mono folder follows it, the multicolor snail keeps its own colors.
Built for AI agents too
Everything works without a prompt: flags, --json, stable exit codes, a JSON Schema for the config, and llms.txt. The agent skill installs svgworm in a Next.js app and fixes every error code.
$ npx skills add jmlweb/svgworm --skill svgworm-nextjsTwo packages, one init, and your icons ship as one cached file.
pnpm add -D svgworm && pnpm add @svgworm/react