How to svg base64 encoding: practical use cases and when to avoid it
- Step 1Name the embedding context first — Is the SVG going into JSON, a React Native
Image, a CSS background, animg src, an email, or a PDF library? The context — not personal preference — determines the encoding. Write it down before encoding anything. - Step 2For JSON / React Native / PDF libs, use Base64 — These consumers expect Base64. For JSON, encode with Include data URI prefix off and store the bare string. For React Native and most PDF libraries, leave the prefix on so the value is a complete
data:image/svg+xml;base64,...URI. - Step 3For CSS background-image, prefer percent-encoding — SVG is mostly ASCII, so percent-encoding produces a shorter string than Base64. Use svg-css-data-uri instead of this tool for CSS backgrounds — reach for Base64 only if your toolchain mangles the percent-encoded quotes.
- Step 4For a reused icon, use an external file — If the same SVG appears on many pages, an external
<img src="/icon.svg">orbackground-image: url(/icon.svg)with cache headers beats any data URI — the browser fetches it once and caches it. Inlining duplicates the bytes everywhere it appears. - Step 5Measure both encodings on your actual file — Run your SVG through this Base64 encoder and through svg-css-data-uri, then compare the two output lengths and the Size overhead metrics. Decide on real numbers, not the textbook 33%.
- Step 6Shrink the source before you encode anything — Whichever encoding you pick, fewer input bytes means fewer output bytes. Strip metadata with svg-metadata-scrubber and minify with svg-pro-minifier before encoding — Base64 multiplies every byte you didn't remove.
Encoding decision matrix
Which embedding method to use per context, and which JAD tool produces it. 'External file' is not an encoding — it's the cacheable alternative to inlining.
| Context | Best choice | Why | JAD tool |
|---|---|---|---|
| JSON API field | Base64 (prefix off) | Keeps the value as a plain string; client adds the data: prefix on render | this tool (svg-to-base64) |
React Native Image source | Base64 (prefix on) | RN's source={{ uri }} reliably accepts data:image/svg+xml;base64,...; percent-encoded SVG is not reliably supported | this tool (svg-to-base64) |
| PDF library (pdfmake, jsPDF) | Base64 | These libraries take SVG/image data as Base64 strings | this tool (svg-to-base64) |
CSS background-image | Percent-encoded data URI | Shorter than Base64 for SVG; encodes ASCII to (mostly) itself | svg-css-data-uri |
HTML img src, reused icon | External .svg file | Cacheable across pages; zero inline weight | minify with svg-pro-minifier, serve as a file |
| Email HTML (some builders) | Base64 (prefix on) | Many email systems block external image domains; an inline data URI bypasses that | this tool (svg-to-base64) |
Base64 vs percent-encoding vs external file
The three options compared on the axes that actually matter for SVG.
| Property | Base64 data URI | Percent-encoded data URI | External file |
|---|---|---|---|
| Typical size vs source | ~+33% (more with prefix) | Usually smaller than Base64 for SVG | 0% inline (separate request) |
| Independently cacheable | No | No | Yes (with cache headers) |
| Extra HTTP request | No | No | Yes (one, then cached) |
| React Native Image support | Reliable | Unreliable | Needs a URL it can fetch |
| Best for CSS background | Workable but larger | Preferred | Good for reused backgrounds |
| JSON-safe as a plain value | Yes (no escaping issues) | Contains characters that need escaping | Store a URL string instead |
Cookbook
Concrete scenarios with the encoding that wins and why — including the cases where Base64 is the wrong answer.
React Native icon — Base64 is the only reliable option
React Native's Image component takes a uri source. It reliably accepts Base64 data URIs but not percent-encoded SVG across versions. Encode with the prefix on and assign it directly.
// Encode with Include data URI prefix = ON, then:
const CHECK = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i…";
<Image
source={{ uri: CHECK }}
style={{ width: 16, height: 16 }}
/>
// Percent-encoded SVG here is flaky — Base64 is the safe choice.CSS background — percent-encoding wins on size
For a CSS background, percent-encoding is shorter. This is the case where you should NOT use this Base64 tool — switch to the CSS Data URI generator instead.
Base64 (this tool):
.bg { background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxu…'); }
→ longer string
Percent-encoded (svg-css-data-uri):
.bg { background-image: url('data:image/svg+xml,%3Csvg xmlns=…'); }
→ typically 5–15% shorter for the same SVG
Use /svg-tools/svg-css-data-uri for CSS backgrounds.Shared icon repeated 40 times — external file wins
An icon used in 40 list rows should be a cacheable file, not 40 inlined Base64 blobs. Inlining multiplies the bytes; an external file is fetched and cached once.
Anti-pattern (Base64 inlined 40×): <img src="data:image/svg+xml;base64,…"> repeated 40 times → 40 × (~+33% bytes) shipped in the HTML, no caching Better: <img src="/icons/check.svg"> ← same file, fetched once, cached → minify it first with /svg-tools/svg-pro-minifier
JSON API returning an inline icon — prefix off
When an API returns an SVG as a field, store the bare Base64 (prefix off) and let the client rebuild the data URI. This keeps the JSON value a clean string and avoids embedding the data: scheme in every record.
Encode with Include data URI prefix = OFF.
Response:
{ "badges": [ { "id": "pro", "svg": "PHN2ZyB4bWxu…" } ] }
Client:
img.src = `data:image/svg+xml;base64,${badge.svg}`;Email with a brand mark — Base64 to dodge blocked domains
Many email environments block external image domains by default, so a hosted SVG simply won't load. An inline Base64 data URI travels inside the message and renders without a fetch (where the client supports SVG at all).
Encode with prefix ON:
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxu…"
width="120" alt="Acme">
Note: SVG support in email clients is uneven — test, and keep
a PNG fallback for clients that don't render SVG.Edge cases and what actually happens
Base64-inlining a reused icon
Anti-patternInlining the same SVG as Base64 in many places ships the bytes (plus ~33%) once per occurrence and defeats browser caching. For any asset used more than once or twice, an external .svg file with cache headers is smaller over the page lifecycle. Inline data URIs are for genuinely one-off or can't-reference-a-file situations.
Percent-encoded SVG in React Native
UnreliableReact Native's Image reliably handles Base64 data URIs but not percent-encoded SVG across versions and platforms. If you tried percent-encoding to save bytes here, switch to Base64 (prefix on) — it's the supported path. Save percent-encoding for CSS in a web context.
Storing a percent-encoded URI as a raw JSON value
Escaping riskPercent-encoded SVG contains characters (<, >, quotes) that JSON must escape, making the value error-prone to hand-edit. Base64 is a clean [A-Za-z0-9+/=] string with no JSON-escaping surprises, which is why it's preferred for API fields even though it's slightly larger.
Assuming Base64 is always smaller
MisconceptionIt isn't — for SVG, percent-encoding is usually smaller because SVG is mostly ASCII that percent-encodes to itself, while Base64 expands every 3 bytes to 4 uniformly. Measure both with the JAD encoders before deciding. Base64's advantages are JSON-safety and React Native support, not size.
Data URI stripped by a Content Security Policy
CSP-dependentA strict CSP with img-src 'self' (no data:) will block any data URI, Base64 or percent-encoded alike. The encoding is fine; the policy rejected the scheme. Either add data: to the relevant CSP directive or serve the SVG as an external file from an allowed origin.
Encoding before minifying
WastefulEncoding a bloated SVG bakes the bloat in and then adds ~33% on top. Always scrub metadata with svg-metadata-scrubber and minify with svg-pro-minifier first; each byte removed is ~1.33 bytes saved in the encoded output.
Email client doesn't render SVG at all
Client gapEven inlined as Base64, SVG support in email clients is uneven (some Outlook versions, some webmail). The encoding is correct — the client lacks SVG rendering. Provide a PNG fallback for those clients; Base64 only solves the blocked-domain problem, not the no-SVG-support problem.
Caching expectations with a data URI
No cachingNeither Base64 nor percent-encoded data URIs are cached separately from the document that contains them — change the page, re-download the icon. If caching matters, that's the signal to use an external file. This is a property of inlining, not of Base64 specifically.
Frequently asked questions
Is Base64 or URL encoding smaller for SVG?
URL (percent) encoding is usually smaller for SVG. SVG is mostly ASCII that percent-encodes to itself or short escapes, while Base64 expands every 3 bytes to 4 uniformly (~33%). For CSS backgrounds use percent-encoding via svg-css-data-uri. Base64's edge is JSON-safety and React Native compatibility, not byte count.
Why is URL encoding better than Base64 for CSS backgrounds?
Because the encoded string is shorter, so your CSS bundle is smaller, and CSS happily accepts percent-encoded data URIs in url(...). Base64 also works in CSS but ships more bytes. Use svg-css-data-uri for backgrounds; keep Base64 for JSON, React Native, and PDF contexts.
Does React Native support percent-encoded SVGs?
Not reliably. React Native's Image source expects Base64 data URIs: source={{ uri: 'data:image/svg+xml;base64,...' }}. Percent-encoded SVG is flaky across RN versions and platforms. Encode with the prefix on and use the Base64 string — this is one of Base64's genuine must-use cases.
When should I use an external file instead of any data URI?
Whenever the SVG is reused or you want browser caching. An external .svg with cache headers is fetched once and reused; a data URI is re-shipped with every page that inlines it. Reserve data URIs (Base64 or percent) for one-off icons or contexts that genuinely can't reference a file.
Can I use a Base64 SVG in a CSS custom property?
Yes: --icon: url('data:image/svg+xml;base64,...'), then background-image: var(--icon). It works in all modern browsers. For pure size though, a percent-encoded value in the same custom property is usually smaller — generate it with svg-css-data-uri.
Should I store Base64 SVGs in a database?
Only for very small, attribute-sized icons. Storing large Base64 blobs in a column is inefficient — they're ~33% bigger than the source and can't be cached by the browser. Store the SVG source (or a file URL) and encode at the edge if needed. The bare Base64 (prefix off) is the right form if you do store it.
Does Base64 hurt performance?
It can, in two ways: extra bytes over the wire (~33%) and no independent caching, so the icon re-downloads with every page change. For a one-off inline icon that's negligible; for a reused asset it adds up. Base64 also adds a tiny decode cost, but that's rarely measurable next to the caching loss.
Is Base64 SVG safe from XSS?
Base64 is encoding, not sanitisation — it doesn't neutralise scripts. An SVG with an inline <script> is still a script once decoded and rendered as SVG. In img src, browsers don't execute SVG scripts; inlined into the DOM they may. Sanitise untrusted SVG with svg-metadata-scrubber and never inline untrusted markup.
Which JAD tool makes the percent-encoded version?
svg-css-data-uri. It produces a URL-encoded data:image/svg+xml,... URI tuned for CSS, which is typically smaller than Base64 for SVG. This page's tool (svg-to-base64) makes the Base64 form for JSON, React Native, email, and PDF use.
Will this tool let me compare the two encodings side by side?
Not in one screen — run your SVG through this Base64 encoder and through svg-css-data-uri separately, then compare the output lengths and Size overhead metrics. Two quick runs give you the real numbers for your specific file, which beats guessing from the 33% rule.
Is Base64 ever the wrong choice for JSON?
Rarely — for JSON, Base64 is usually right because it's a clean string with no escaping issues. The only caveat is size: a large SVG bloats the payload by ~33%. If the SVG is big and reused, return a URL in the JSON and let the client fetch the file instead of embedding the bytes.
Do I need the prefix on or off for my use case?
On for anything that consumes a complete URI directly — img src, CSS, React Native source. Off for JSON fields, database columns, or any consumer that prepends its own data: scheme. The checkbox is the tool's only setting; pick based on whether the target wants a full URI or just the bytes.
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.