How to automate svg data uri generation for css build pipelines
- Step 1Decide: PostCSS plugin or runner/script — If your data URIs live in CSS you author, a PostCSS plugin that resolves
inline-svg()references is the lowest-friction path. If you need a programmatic step (CI job, codegen), pair a local @jadapps/runner and call its engine, or write a small script using the same escaping rules. - Step 2Option A — install postcss-inline-svg —
npm install --save-dev postcss-inline-svg. This plugin reads SVGs from disk and replacesinline-svg('path/to/icon.svg')in your CSS with URL-encoded data URIs at build time, and supports colour overrides per reference. - Step 3Option A — configure the PostCSS pipeline — In
postcss.config.js:plugins: { 'postcss-inline-svg': { paths: ['./src/icons'] } }. Then author rules likebackground-image: inline-svg('search.svg', fill: #ff0000);and let the build inline them. - Step 4Option B — pair a local runner — JAD's hosted API never accepts uploads —
POST /api/v1/tools/svg-css-data-uri/runreturns a 400 telling you to pair a runner. Install@jadapps/runner, which listens on127.0.0.1:9789, and dispatch each SVG to/v1/tools/svg-css-data-uri/runwith an optionalclassNamein the options. - Step 5Fetch the contract first — Before building payloads, GET
/api/v1/tools/svg-css-data-urifor the machine-readable schema. For this tool the web option set is empty; the engine accepts aclassName(defaulticon) that becomes.icon-<className>. - Step 6Wire it into the build, not the repo — Run the encode step as part of your CSS build and gitignore the output. Commit the source SVGs (and your PostCSS config) so the generated CSS is reproducible and never shows up as noise in diffs.
Three ways to batch-encode
What each route is good at. The web tool is one-file-at-a-time and best for spot checks; the other two scale.
| Approach | How it scales | Best for |
|---|---|---|
| Web CSS Data-URI Generator | One SVG per run; manual upload/paste | Spot-checking a single icon's output or copying one rule |
| postcss-inline-svg | Resolves every inline-svg() reference at CSS build time | Data URIs authored directly in your stylesheets, with colour overrides |
| Paired @jadapps/runner | Script over a folder; one localhost call per file | CI/codegen where files must stay on your machine and you want JAD's exact encoding |
JAD encode contract for this tool
What the engine actually does per file. The web UI exposes no options; the runner/engine path adds a single className.
| Aspect | Value |
|---|---|
| Files per web run | One (this tool is not multi-file; only the sprite builder accepts multiple) |
| Encoding | URL/percent-encoding, charset=utf-8 — never base64 |
| Web UI options | None |
| Engine/runner option | className (string, default icon) → selector .icon-<className> |
| Output | A full CSS rule: background-image + no-repeat + center + contain |
| Hosted API uploads | Rejected with 400 — pair a local runner instead |
| Tier | Pro |
Cookbook
Copy-paste-able recipes for the two scalable routes, plus the source-control rule that keeps generated CSS tidy.
postcss-inline-svg with a colour override
Author a normal-looking CSS rule; the plugin reads the file from disk, applies the fill, URL-encodes, and inlines at build time.
/* postcss.config.js */
module.exports = {
plugins: { 'postcss-inline-svg': { paths: ['./src/icons'] } }
};
/* source CSS */
.btn-search {
background-image: inline-svg('search.svg', fill: #ff0000);
}
/* built CSS (plugin output) */
.btn-search {
background-image: url("data:image/svg+xml;charset=utf-8, ... fill='%23ff0000' ... ");
}The hosted API is upload-free
POSTing SVG content to JAD's API does not encode it server-side. The response points you at the schema and a local runner endpoint.
POST /api/v1/tools/svg-css-data-uri/run (with a body)
→ 400 Runner required
{
"error": "Runner required",
"schemaEndpoint": ".../api/v1/tools/svg-css-data-uri",
"runnerEndpoint": "http://127.0.0.1:9789/v1/tools/svg-css-data-uri/run",
"installRunner": ".../docs/runner"
}Drive a paired runner over a folder
Install @jadapps/runner, then loop your icons through localhost. The runner runs the same engine in-process, so the URI matches the web tool; className sets the selector.
# pseudo-script
for f in ./icons/*.svg; do
curl -s http://127.0.0.1:9789/v1/tools/svg-css-data-uri/run \
-F file=@"$f" \
-F 'options={"className":"'"$(basename "$f" .svg)"'"}' \
>> icons.generated.css
done
# each block: .icon-<name> { background-image: url("data:...") ... }Deterministic class names
Left to itself, the web tool derives the class from the filename. In automation, set className explicitly so selectors don't depend on file naming.
options = { "className": "search" }
→ .icon-search { ... }
options = {} // default
→ .icon-icon { ... } // engine default base is "icon"
Web tool (no option):
→ .icon-<filename-stem>Keep generated CSS out of git
Commit sources, generate output. This keeps diffs reviewable and avoids merge conflicts on machine-generated strings.
# .gitignore /src/styles/icons.generated.css # committed /src/icons/*.svg /postcss.config.js # build step regenerates the CSS in CI / on dev start
Edge cases and what actually happens
POSTing SVG content to the hosted API
400 by designJAD's API/MCP layer never accepts uploads. POST /api/v1/tools/svg-css-data-uri/run with a body returns a 400 whose payload includes the schema endpoint and the localhost runner URL. Automation must target a paired @jadapps/runner, not the hosted endpoint.
Expecting the web tool to take a folder
One file onlyThe web CSS Data-URI Generator processes a single SVG per run and is not a multi-file tool (only the sprite builder accepts multiple inputs). For a folder, use a PostCSS plugin or a runner-driven script.
Assuming a base64 build output
URL-encoded onlyBoth the engine and postcss-inline-svg produce URL-encoded data URIs. If a downstream tool requires base64, encode with svg-to-base64 instead; this tool has no base64 mode.
Committing the generated CSS
AvoidChecking in machine-generated data-URI CSS creates large, unreviewable diffs every time any icon changes. Commit source SVGs and the build config; gitignore the generated stylesheet and regenerate it in CI.
Colour override in plugin but not in the JAD web tool
Different capabilitiespostcss-inline-svg can recolour before encoding via fill:/stroke: arguments. The JAD CSS Data-URI Generator does not recolour — it encodes the markup as-is. To recolour first with JAD, run svg-hex-swapper or svg-monochrome-converter, then encode.
Filename-derived class names collide
Selector clashTwo files that sanitise to the same stem (e.g. Arrow.svg and arrow.svg) both yield .icon-arrow. In automation, pass an explicit, unique className per file rather than relying on the filename.
Runner not installed or not running
Connection refusedCalls to 127.0.0.1:9789 fail if no @jadapps/runner is paired and listening. Install it from the runner docs and confirm it's up before the build step runs; otherwise the batch produces nothing.
Caching coupling across a large generated set
Performance caveatBatch-inlining a whole icon set into one stylesheet means any single icon change invalidates the entire CSS cache. For large sets weigh this against external files or a sprite — see the data-URI vs external-file guide.
Frequently asked questions
Can the JAD web tool batch-process a folder of SVGs?
No. The web CSS Data-URI Generator encodes one SVG per run. For batches, use a PostCSS plugin in your CSS build or drive a paired @jadapps/runner over each file in a script.
Does the JAD API accept SVG uploads for batch encoding?
No. The hosted API is intentionally upload-free — POSTing content returns a 400 with pairing instructions. Files are processed by a local @jadapps/runner on 127.0.0.1, so they never leave your network.
What is postcss-inline-svg?
A PostCSS plugin that reads SVG files from disk and replaces inline-svg('icon.svg') references in your CSS with URL-encoded data URIs at build time. It also supports per-reference colour overrides like inline-svg('icon.svg', fill: #ff0000).
Can I set the colour during batch encoding?
With postcss-inline-svg, yes — pass fill:/stroke: in the reference. The JAD encoder itself does not recolour; recolour first with svg-hex-swapper or svg-monochrome-converter, then encode.
How do I control the generated class name in automation?
Pass a className in the runner/engine options. The selector becomes .icon-<className> (default base icon). The web tool, by contrast, derives the class from the uploaded filename.
Is the runner's output the same as the web tool's?
Yes for the encoded URI — both run the same engine logic (URL-encoding with charset=utf-8, double-quotes → single-quotes, the full CSS rule). The class name source differs: filename in the browser, className option via the runner.
Should I commit the generated CSS?
No. Commit the source SVGs and your build config, gitignore the generated stylesheet, and regenerate it at build time. Committing it produces huge diffs on every icon change.
Does this produce base64 or URL-encoded output?
URL-encoded. Neither the engine nor postcss-inline-svg emits base64. Use svg-to-base64 if a build tool specifically requires base64.
What tier is required to run this on JAD?
Pro. The CSS Data-URI Generator is a Pro-tier tool, and runner-accelerated execution is a Pro feature.
How do I get the machine-readable schema for the tool?
GET /api/v1/tools/svg-css-data-uri. It returns the option schema, tier, and execution mode so SDK/MCP clients can build payloads for the local runner.
Can I cache-bust inlined icons?
Inlined data URIs are part of the CSS, so they're invalidated whenever the content-hashed CSS filename changes. There's no per-icon cache-busting for inlined assets — that's a reason to keep frequently-changing icons external.
What about very large icon sets?
Batch-inlining everything bloats the stylesheet and couples cache invalidation. For big sets, prefer external files or an SVG sprite and reserve data URIs for critical-path assets.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.