Next.js App Router setup
Set svgworm up in a Next.js App Router app in five steps. You end up with a hashed sprite in public/icons/, typed icon names, and an Icon component that runs only on the server.
Requires Node ^22.20 || >=24.11.
Steps
-
Put your SVG files in
icons/. -
Install and build the sprite:
pnpm add -D svgworm pnpm add @svgworm/react pnpm svgworm --source iconsThis writes the sprite to
public/icons/and the manifest and types tosvgworm/:public/icons/icons.<hash>.svg sprite (and icons.stack.<hash>.svg when an icon needs it) svgworm/icons.js manifest (data only) svgworm/icons.d.ts types: IconName and the manifest shape svgworm/manifest.json same manifest, for scripts and templates -
Create the component once, in a Server Component file:
// components/icon.tsx import { createIcon } from "@svgworm/react"; import { manifest } from "../svgworm/icons.js"; export const Icon = createIcon(manifest); -
Run the CLI before
devandbuild:{ "scripts": { "predev": "svgworm", "prebuild": "svgworm" } } -
Use it anywhere on the server:
import { Icon } from "@/components/icon"; export const Nav = () => ( <nav> <Icon name="home" /> <Icon name="brand/sunset" width={32} height={32} /> <Icon name="home" title="Go home" /> </nav> );The icon is
aria-hiddenunless you passtitleorlabel. An unknownnameis a type error.
Cache for a year
Next serves public/ with max-age=0. The file names are content-hashed, so a long cache is safe:
// next.config.ts
export default {
async headers() {
return [
{
source: "/icons/:file*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
];
},
};
basePath
Working example
examples/next-app-router is a complete app with these steps, built with Turbopack and checked in CI for no icon code in client chunks.
Next
- CLI reference: every command, flag and exit code.
- Config:
svgworm.config.jsonand per-icon color overrides. - Using Astro? Read the Astro setup.