svgforge

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-image via fragment identifiers,
- symbol: sprites using the
<symbol> element, referenced via <use href="#id"> (inline) or href="sprite.svg#id" (external) — the modern, more convenient variant,
- defs: sprites using the
<defs> element, the same technique as <symbol>, but with the viewBox duplicated 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. If you need a CLI, there's a separate project svgforge-cli.
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
svgforge and svgforge-cli for easier testing
- 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-image you can use the stack mode, 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
- 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
To install svgforge in your project, run:
npm install @svgforge/svgforge
Help us test the upcoming v3
The upcoming v3 release (rebuilt on modern dependencies, see Changes compared to svg-sprite) is available as a beta and is looking for real-world testing:
npm install @svgforge/svgforge@beta
Found a bug, a regression or a rough edge? Please open an issue — every report makes the stable release better.
Getting started
Crafting a sprite with svgforge typically follows these steps:
The procedure is the very same for all supported sprite types («modes»).
Usage pattern
Hint: Even the library is ESM only, since Node 22+ 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';
const config = {
};
const spriter = new SVGSpriter(config);
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')
);
const { result } = await spriter.compileAsync();
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>,
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:
const config = {
dest: '.',
log: null,
shape: {
id: {
separator: '--',
generator: function () { },
pseudo: '~'
},
dimension: {
maxWidth: 2000,
maxHeight: 2000,
precision: 2,
attributes: false,
},
spacing: {
padding: 0,
box: 'content'
},
transform: ['svgo'],
meta: null,
align: null,
dest: null
},
svg: {
xmlDeclaration: true,
doctypeDeclaration: true,
namespaceIDs: true,
namespaceIDPrefix: '',
namespaceClassnames: true,
dimensionAttributes: true
},
variables: {}
}
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,
defs: true,
symbol: true,
stack: true
}
}
To further configure a sprite, pass in an object with configuration options:
const config = {
mode: {
symbol: {
}
}
}
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.
const config = {
mode: {
<mode>: {
dest: "<mode>",
prefix: "svg-%s",
dimensions: "-dims",
sprite: "svg/sprite.<mode>.svg",
bust: true || false,
render: {
},
example: false
}
}
}
Basic examples
Standalone sprite
Foreground image sprite with <symbol> elements (for being <use>d in your HTML source):
const config = {
mode: {
symbol: {
inline: true
}
}
}
Sprite with CSS resource
«symbol» sprite with a CSS stylesheet:
const config = {
mode: {
symbol: {
render: {
css: true
}
}
}
}
Multiple sprites
<symbol> sprite and an SVG stack all at once:
const config = {
mode: {
symbol: true,
stack: true
}
}
No sprite at all
mode-less run, returning the optimized SVG shapes only:
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.
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.dest as the CSS stylesheet location.
- If you just enabled CSS output by setting
mode.<mode>.render.css to true, the default value applies, which is mode.<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 -g
A typical example could look like this:
svgforge --symbol --symbol-render-css --symbol-example --dest=out assets/*.svg
Please 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
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 joschi@kuphal.net / @jkphl. The contained example SVG icons are part of the Tango Icon Library and belong to the Public Domain.