@svgforge/svgforge
v3.2.0
Published
SVG sprites & stacks galore — A low-level Node.js module that takes a bunch of SVG files, optimizes them and bakes them into SVG sprites of several types along with suitable stylesheet resources (e.g. CSS)
Maintainers
Readme
svgforge
If you need only a CLI, there's a separate project svgforge-cli — you only have to install the CLI, but the documentation here may still be relevant.
svgforge is a low-level Node.js module that takes a bunch of SVG files, optimizes them and bakes them into SVG sprites of several types:
- view: tiled sprites with pre-defined
<view>elements, useful for foreground images via SVG fragment identifiers, - stack: SVG stacks, also usable as CSS
background-imagevia fragment identifiers, - symbol: sprites using the
<symbol>element, referenced via<use href="#id">(inline) orhref="sprite.svg#id"(external) — the modern, more convenient variant, - defs: sprites using the
<defs>element, the same technique as<symbol>, but with theviewBoxduplicated on every<use>.
You can explore the API with DeepWiki, which can also help you create a configuration file or short script for building the icons.
There is also a Github page, with some tutorials how to use svgforge and related projects.
Changes compared to svg-sprite
This is a fork of svg-sprite with lots of changes.
The idea is to have it as a drop-in replacement of svg-sprite, with the exception of the removed CSS preprocessor support and old school sprite technique.
- Complete rewrite from CJS to ESM
- All node dependencies are upgraded
- You need Node.js version >= 24
- Split package to
svgforgeandsvgforge-clifor easier testing - Block deep imports: the
exportsmap only exposes the main entry point,./utilsand the legacy./lib/svg-sprite/utils/index.jsalias — every otherlib/path is blocked - Drop grunt and gulp (you can still use it with a few lines of code)
- Replace glob with native fs.glob
- Remove SCSS, LESS and Stylus support, it was only useful for sprite generation.
- Replace prettysize npm package with a small helper function (unmaintained)
- Replace async npm package with native ES6 Promise API
- Replace import-lazy npm package with native lazy imports.
- Replace winston npm package with native logger.
- Replace xpath with @xmldom/xmldom that is already installed (xpath uses insecure
eval). - Replace cssom with css-tree because the package is not maintained anymore.
- Replace lodash with native ES6 + utility functions
- Replace mustache with ventojs templates.
- Remove support for the sprite technique (CSS background position). I've found it antique and not required anymore and it simplifies the code a lot! If you want to use icons as
background-imageyou can use thestackmode, and then:background: url(icon.svg#ID). See here: https://css-tricks.com/svg-fragment-identifiers-work/#syntax-for-css - Improved example templates with copy id button for each icon, using a
twig-like syntax. - Finally all tests are fixed with over 90% coverage and use Node.js's native test runner instead of Jest
- The CLI now has tests.
It comes with a set of Vento templates for creating stylesheets in good ol' CSS. Tweaking the templates or even adding your own custom output format is really easy, just as switching on the generation of an HTML example document along with your sprite.
For an up-to-date list of browsers supporting SVG fragment identifiers in particular (required for <defs> and <symbol> sprites as well as SVG stacks) please refer to caniuse.com.
Table of contents
- Installation
- Getting started
- Configuration basics
- Advanced techniques
- Command line usage
- Known problems / To-do
- Changelog
- Legal
Installation
To install svgforge in your project, run:
npm install @svgforge/svgforgeThe @resvg/resvg-js peer dependency is
only used for an edge case: SVGs that have neither a viewBox nor
width/height attributes — which is unusual, as SVG tools almost always write a
viewBox. Those shapes get their dimensions from rendering the image; if the package is
unavailable, they are skipped with a logged warning naming the install command
(npm install @resvg/resvg-js). isResvgAvailable() (exported from the utils entry
point) reports whether the fallback is available.
Getting started
Crafting a sprite with svgforge typically follows these steps:
- You create an instance of the SVGSpriter, passing a main configuration object to the constructor.
- You register a couple of SVG source files for processing.
- You trigger the compilation process and receive the generated files (sprite, CSS, example documents etc.).
The procedure is the very same for all supported sprite types («modes»).
Usage pattern
Hint: The library is ESM-only. Since Node.js 24 you can also use CJS (require) instead of ESM imports.
import fs from 'node:fs';
import path from 'node:path';
import SVGSpriter from '@svgforge/svgforge';
// Define your configuration
const config = {
// ...
};
// 1. Create spriter instance
const spriter = new SVGSpriter(config);
// 2. Add SVG source files
spriter.add(
'assets/svg-1.svg',
null,
fs.readFileSync('assets/svg-1.svg', 'utf8')
);
spriter.add(
'assets/svg-2.svg',
null,
fs.readFileSync('assets/svg-2.svg', 'utf8')
);
// 3. Compile the sprite asynchronously
const { result } = await spriter.compileAsync();
// Write generated files to disk
for (const mode of Object.values(result)) {
for (const resource of Object.values(mode)) {
fs.mkdirSync(path.dirname(resource.path), { recursive: true });
fs.writeFileSync(resource.path, resource.contents);
}
}
As you can see, big parts of the above are dealing with disk I/O by writing the resulting vinyl files to disk yourself.
Configuration basics
Of course you noticed the config variable passed to the constructor in the above example. This is svgforge's main configuration — an Object with the following properties:
{
dest: <String>, // Main output directory
log: <String|Logger>, // Logging verbosity or custom logger
shape: <Object>, // SVG shape configuration
svg: <Object>, // Common SVG options
variables: <Object>, // Custom templating variables
mode: <Object> // Output mode configurations
}If you don't provide a configuration object altogether, svgforge uses built-in defaults for these properties, so in fact, they are all optional. However, you will need to enable at least one output mode (mode property) to get reasonable results (i.e. a sprite of some type).
General configuration options
Many configuration properties (all except mode) apply to all sprites created by the same spriter instance. The default values are:
// Common svgforge config options and their default values
const config = {
dest: '.', // Main output directory
log: null, // Logging verbosity (default: no logging)
shape: { // SVG shape related options
id: { // SVG shape ID related options
separator: '--', // Separator for directory name traversal
generator: function () { /*...*/ }, // SVG shape ID generator callback
pseudo: '~' // File name separator for shape states (e.g. ':hover')
},
dimension: {// Dimension related options
maxWidth: 2000, // Max. shape width
maxHeight: 2000, // Max. shape height
precision: 2, // Floating point precision
attributes: false, // Width and height attributes on embedded shapes
},
spacing: { // Spacing related options
padding: 0, // Padding around all shapes
box: 'content' // Padding strategy (similar to CSS `box-sizing`)
},
transform: ['svgo'], // List of transformations / optimizations
meta: null, // Path to YAML file with meta / accessibility data
dest: null // Output directory for optimized intermediate SVG shapes
},
svg: { // General options for created SVG files
xmlDeclaration: true, // Add XML declaration to SVG sprite
doctypeDeclaration: true, // Add DOCTYPE declaration to SVG sprite
namespaceIDs: true, // Add namespace token to all IDs in SVG shapes
namespaceIDPrefix: '', // Add a prefix to the automatically generated namespaceIDs
namespaceClassnames: true, // Add namespace token to all CSS class names in SVG shapes
dimensionAttributes: true, // Width and height attributes on the sprite
rootAttributes: {} // Additional attributes for the outermost <svg> element
},
variables: {} // Custom Vento templating variables and functions
}Please refer to the configuration documentation for details.
Output modes
At the moment, svgforge supports four different output modes (i.e. sprite types), each of them has its own characteristics and use cases. It's up to you to decide which sprite type is the best choice for your project. The mode option controls which sprite types are created. You may enable more than one output mode at a time — svgforge will happily create several sprites in parallel.
To enable the creation of a specific sprite type with default values, simply set the appropriate mode property to true:
const config = {
mode: {
view: true, // Create a «view» sprite
defs: true, // Create a «defs» sprite
symbol: true, // Create a «symbol» sprite
stack: true // Create a «stack» sprite
}
}To further configure a sprite, pass in an object with configuration options:
// «symbol» sprite with CSS stylesheet resource
const config = {
mode: {
symbol: {
// Configuration for the «symbol» sprite
// ...
}
}
}Common mode properties
Many mode properties are shared between the different sprite types, but there are also type specific options. Please refer to the configuration documentation for a complete list of settings.
// Common mode properties
const config = {
mode: {
<mode>: {
dest: "<mode>", // Mode specific output directory
prefix: "svg-%s", // Prefix for CSS selectors
dimensions: "-dims", // Suffix for dimension CSS selectors
sprite: "svg/sprite.<mode>.svg", // Sprite path and name
bust: true || false, // Cache busting (mode dependent default value)
render: { // Stylesheet rendering definitions
/* -------------------------------------------
css: false, // CSS stylesheet options
<custom>: ... // Custom stylesheet options
------------------------------------------- */
},
example: false // Create an HTML example document
}
}
}Basic examples
Standalone sprite
Foreground image sprite with <symbol> elements (for being <use>d in your HTML source):
// «symbol» sprite with CSS stylesheet resource
const config = {
mode: {
symbol: { // Create a «symbol» sprite
inline: true // Prepare for inline embedding
}
}
}Sprite with CSS resource
«symbol» sprite with a CSS stylesheet:
// «symbol» sprite with CSS stylesheet resource
const config = {
mode: {
symbol: { // Create a «symbol» sprite
render: {
css: true // Render a CSS stylesheet
}
}
}
}Multiple sprites
<symbol> sprite and an SVG stack all at once:
// «symbol» and «stack» sprites in parallel
const config = {
mode: {
symbol: true,
stack: true
}
}No sprite at all
mode-less run, returning the optimized SVG shapes only:
// Just optimize source SVG files, create no sprite
const config = {
shape: {
dest: 'path/to/out/dir'
}
}Output destinations
Depending on your particular configuration, svgforge creates a lot of files that partly refer to each other. Several configuration options are controlling the exact location of each file, and you are well advised to spend a moment understanding how they interrelate with each other.
Relative destination paths refer to their ancestors as shown in the following scheme, with the current working directory being the ultimate base.
| Destination option | Default | Comment |
|----------------------------------|----------------------|---------|
| cwd $ | <dest>/ | Main output directory |
| <mode.view.dest>/ | view | «view» base directory |
| <mode.view.sprite> | svg/sprite.view.svg | Sprite location |
| (rendering resources) | | Created by the respective modes, e.g. defs/symbol/stack |
| <mode.defs.dest>/ | defs | «defs» base directory |
| ... | | |
| <mode.symbol.dest>/ | symbol | «symbol» base directory |
| ... | | |
| <mode.stack.dest>/ | stack | «stack» base directory |
By default, stylesheet resources are generated directly into the respective mode's base directory.
"Oh wait! Didn't you say that svgforge doesn't access the file system? So why do you need output directories at all?" — Well, good point. svgforge uses vinyl file objects to pass along virtual resources and to specify where they are intended to be located. This is especially important for relative file paths (e.g. the path of an SVG sprite as used by a CSS stylesheet).
CSS resources and the sprite location
Special care needs to be taken when you create a sprite with a CSS stylesheet resource (the «defs», «symbol» and «stack» modes). In this case, calculating the correct relative SVG sprite path as used by the stylesheet can become tricky, as your final CSS file doesn't necessarily lie side by side with the sprite:
- If you truly configured CSS output, svgforge uses your custom
mode.<mode>.render.css.destas the CSS stylesheet location. - If you just enabled CSS output by setting
mode.<mode>.render.csstotrue, the default value applies, which ismode.<mode>.dest / "sprite.css". - The same holds true when you don't enable CSS output at all. svgforge then simply assumes that the CSS file will be created where the defaults would put it, which is again
mode.<mode>.dest / "sprite.css".
So even if you don't enable plain CSS output explicitly, please make sure to set mode.<mode>.dest to where your final CSS file is intended to be.
Full configuration documentation
The complete configuration documentation including all options can be found here.
Advanced techniques
Meta data injection
In order to improve accessibility, svgforge can read meta data from a YAML file and inject <title> and <description> elements into your SVGs. Please refer to the meta data injection guide for details.
Tweaking and adding output formats
svgforge uses Vento templates for rendering the various CSS resources. This makes it very easy to tailor the generated CSS resources to your needs or add completely new output formats. Please refer to the templating guide to learn about the details.
Command line usage
The command line interface has been split out into the separate svgforge-cli package. Install it globally to get the svgforge command:
npm install @svgforge/svgforge-cli -gA typical example could look like this:
svgforge --symbol --symbol-render-css --symbol-example --dest=out assets/*.svgPlease refer to the CLI guide for further details.
Known problems / To-do
- SVGO does not minify element IDs when there are
<style>or<script>elements contained in the file
See docs/roadmap.md for open items and postponed changes —
for example making the optional @resvg/resvg-js
dimension fallback an optional peer dependency, which is a breaking change and therefore
targeted at 4.x.
Changelog
Please refer to the Changelog.md or the git commits for a complete release history.
Legal
Copyright © 2026 svgforge. svgforge is licensed under the terms of the MIT license. The original author is Joschi Kuphal [email protected] / @jkphl. The contained example SVG icons are part of the Tango Icon Library and belong to the Public Domain.
