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

  1. Put your SVG files in icons/.

  2. Install and build the sprite:

    pnpm add -D svgworm
    pnpm add @svgworm/react
    pnpm svgworm --source icons

    This writes the sprite to public/icons/ and the manifest and types to svgworm/:

    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
  3. 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);
  4. Run the CLI before dev and build:

    { "scripts": { "predev": "svgworm", "prebuild": "svgworm" } }
  5. 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-hidden unless you pass title or label. An unknown name is 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

Edit this page on GitHub