SVG to Base64: Encode SVGs for CSS & HTML (With or Without Base64)

By Hieu Dinh

If you have ever wanted to drop an icon into a stylesheet without shipping a separate file, encoding SVG to Base64 is one way to do it. A Base64 data URI lets you embed the entire SVG directly inside a background-image, an <img> tag, or a JSON payload, so the browser renders it without making a second HTTP request. That single-request property is the whole appeal: the markup travels with the document, there is no extra round trip, and nothing breaks if a CDN path changes.

This guide walks through every practical way to convert SVG to Base64 (command line, online encoders, JavaScript, and build tools), shows real data:image/svg+xml;base64,... snippets you can paste into CSS, and then gives you the honest counterpoint most converters skip: for SVG specifically, Base64 is usually the wrong choice. Because SVG is plain text, URL-encoding the same file is typically smaller and gzips better, and inline <svg> is often better still. We will cover all three so you can pick the right one instead of reaching for Base64 by reflex.

How to Convert SVG to Base64

There are four common ways to turn an SVG file into a Base64 string. Pick whichever fits your workflow.

Command line

On macOS and Linux, the built-in base64 utility does the job in one line. This is the fastest path for a one-off encode:

# Encode an SVG file to a raw Base64 string
base64 -i icon.svg

# Write the result to a file instead of the terminal
base64 -i icon.svg -o icon.b64

# Build a full CSS-ready data URI in one go
printf 'background-image:url("data:image/svg+xml;base64,%s");' "$(base64 -i icon.svg)"

On Linux the flag is slightly different (base64 icon.svg reads from the file directly, or base64 -w 0 icon.svg to disable line wrapping). Always strip line breaks before pasting into CSS, or the data URI will break.

Online encoders

If you just need a string and do not want to touch a terminal, paste your SVG into a browser-based encoder. Tools like base64.guru and fffuel's eeencode output both Base64 and URL-encoded versions side by side, which makes the size difference obvious. Be mindful that you are uploading your markup to a third party, so do not paste anything proprietary.

JavaScript (browser and Node)

In the browser, btoa() Base64-encodes a string, but it chokes on non-Latin1 characters, so wrap it with unescape(encodeURIComponent(...)) for safety:

// Encode an inline SVG string in the browser
const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 12h16"/></svg>';
const base64 = btoa(unescape(encodeURIComponent(svg)));
const dataUri = `data:image/svg+xml;base64,${base64}`;

document.querySelector('#icon').src = dataUri;

To encode a file the user selects, use FileReader, which produces a ready-to-use data URI directly:

// Read a user-selected .svg file and get a data URI
const handleFile = (file) => {
  const reader = new FileReader();
  reader.onload = () => console.log(reader.result); // data:image/svg+xml;base64,...
  reader.readAsDataURL(file);
};

In Node, skip btoa and use a Buffer:

import { readFileSync } from 'node:fs';

const svg = readFileSync('icon.svg');
const dataUri = `data:image/svg+xml;base64,${svg.toString('base64')}`;

Build tools

Most bundlers can inline small SVGs as data URIs automatically. Webpack's asset/inline type and Vite's assetsInlineLimit will convert assets under a size threshold into data URIs at build time, so you never hand-encode anything. The catch: by default many tools emit Base64, which (as the next section explains) is usually the larger option for SVG. Configure them to URL-encode SVG when you can.

Using the Base64 string in CSS and HTML

Once you have the string, the data URI drops straight into CSS:

.logo {
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTQgMTJoMTYiLz48L3N2Zz4=");
  width: 24px;
  height: 24px;
}

Or in an <img> tag:

<img
  src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTQgMTJoMTYiLz48L3N2Zz4="
  alt="Logo"
  width="24"
  height="24"
/>

The URL-encoded (non-Base64) alternative skips the encoding overhead entirely. Notice it is human-readable, which is a real debugging advantage:

.logo {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12h16'/%3E%3C/svg%3E");
}

The trick with URL-encoded SVG is that you do not have to escape everything. Swapping double quotes for single quotes inside the SVG and only encoding the characters CSS actually cares about (<, >, #, and a few others) keeps the string short and legible.

Base64 vs URL-Encoded vs Inline SVG

Here is the part most "svg to base64" tutorials leave out. Base64 is the default people reach for, but it is almost never the best option for SVG. The reason is simple: SVG is already text.

Base64 encoding inflates any payload by roughly 33% because it represents 3 bytes of data with 4 ASCII characters. That overhead is unavoidable and it applies whether the source is a binary JPEG or a text-based SVG. For a photo there is no alternative, so the 33% is a fair price. But an SVG is XML, mostly made of ASCII characters that survive URL-encoding as themselves. URL-encoding only expands the handful of reserved characters, so the result is typically 20-30% smaller than the Base64 version of the same file.

Size is only half the story. The bigger win is compression. Your server almost certainly serves CSS with gzip or Brotli, and raw SVG markup compresses extremely well because it is repetitive (<path, fill=, coordinate runs). Base64 turns that repetitive text into high-entropy noise that compresses far worse. So Base64 loses twice: it is bigger before compression and it compresses worse after. The classic CSS-Tricks article "Probably Don't Base64 SVG" made exactly this case years ago, and it still holds.

And then there is inline <svg>, which skips data URIs altogether. Putting the SVG markup directly in your HTML means zero encoding overhead, full CSS and JavaScript control over individual paths (you can animate or recolor them with currentColor), and no base64 bloat. The downside is that inline SVG is not independently cacheable, and repeating the same icon across a page duplicates its markup.

MethodSize overheadCacheableReadable / debuggableBest for
Inline <svg>NoneNo (lives in HTML)YesIcons you need to style or animate per element
URL-encoded data URIMinimal (only reserved chars)Yes (in a CSS file)YesMost CSS background-image use cases
Base64 data URI~33% largerYes (in a CSS file)NoSVGs with embedded raster images, or tooling that mishandles raw markup

Decision rule: Reach for inline SVG when you need per-element styling or animation. Use a URL-encoded data URI for CSS backgrounds, which is the right default for the vast majority of cases. Only fall back to Base64 when your SVG embeds binary raster data (an actual <image> with a JPEG inside), or when a build pipeline or CMS mangles raw < and # characters and Base64 is the path of least resistance. Encoding to Base64 should be a deliberate exception, not the habit. If you also work with raster images, the same tradeoffs and a broader walkthrough live in our guide to encoding any image to Base64.

Optimize the SVG First

Whichever encoding you choose, the single most effective thing you can do is shrink the source SVG before you encode it. The data URI string is a direct function of the file's byte size, so every byte you trim from the SVG comes straight out of the encoded result. Exported SVGs are notoriously bloated: editors like Illustrator and Figma pack in editor metadata, comments, empty groups, redundant id attributes, full-precision coordinates with ten decimal places, and inline styles that could be attributes.

A typical icon exported from a design tool can drop 40-70% in size after optimization, with no visible change. Run it through an optimizer first and the encoded data URI shrinks by the same proportion.

The standard tool for this is SVGO, which strips metadata, collapses transforms, rounds coordinates, and removes hidden elements. A quick pass looks like this:

# Minify a single SVG before encoding it
npx svgo icon.svg -o icon.min.svg

# Then encode the minified version
base64 -i icon.min.svg

If you would rather not wire up a CLI for every file, or you are optimizing a folder of SVGs alongside the rest of your image assets, Compresto handles SVG minification natively on your Mac. It strips the same junk SVGO does, batch-processes an entire folder of icons at once, and runs fully offline so your markup never leaves your machine. To be clear about what it does and does not do: Compresto shrinks the source SVG (and your PNGs, JPEGs, WebP, GIFs, video, and PDFs in the same batch), but it does not output Base64 strings. The workflow is optimize first with Compresto or SVGO, then run the lean file through whichever encoder you chose above. A smaller source means a smaller data URI either way. For a deeper dive into SVG cleanup specifically, see our SVG optimizer guide.

FAQ

Should I use Base64 or URL-encoding for SVG data URIs?

URL-encoding, in almost every case. Because SVG is text, URL-encoding is typically 20-30% smaller than Base64 and compresses far better under gzip or Brotli. Reserve Base64 for SVGs that embed binary raster data, or for tooling that cannot handle raw < and # characters in a stylesheet.

Does encoding SVG to Base64 make the file bigger?

Yes. Base64 adds roughly 33% overhead because it encodes 3 bytes as 4 characters. That cost is unavoidable for binary formats, but for text-based SVG it is wasteful compared to URL-encoding, which only expands a few reserved characters.

Why is my Base64 SVG not showing up in CSS?

The most common causes are a missing or wrong MIME type (it must be data:image/svg+xml;base64,), line breaks left in the Base64 string, or unescaped characters in a URL-encoded data URI. Use base64 -w 0 (Linux) or strip newlines, and double-check the prefix is exactly right.

Can I convert SVG to Base64 without an online tool?

Yes. On macOS or Linux run base64 -i icon.svg in the terminal, or use btoa(unescape(encodeURIComponent(svg))) in browser JavaScript and Buffer.from(svg).toString('base64') in Node. None of these send your file anywhere.

Should I inline the SVG instead of using a data URI?

If you need to style, recolor (via currentColor), or animate the SVG per element, inline <svg> is the better choice because it gives full CSS and JS access with zero encoding overhead. Data URIs win when you want the asset cached in a CSS file and reused across pages.

Bottom Line

Converting SVG to Base64 is easy: one base64 command, a btoa() call, or an online encoder gets you a data URI you can paste into CSS or HTML for single-request embedding. But easy is not the same as optimal. For SVG, Base64's ~33% overhead and poor compression mean it loses to URL-encoded data URIs in nearly every real scenario, and inline <svg> often beats both when you need styling control.

So the practical playbook is: optimize the source SVG first with SVGO or Compresto so the string is as small as possible, then choose URL-encoding by default, inline SVG when you need control, and Base64 only as a deliberate exception. Pair that with the rest of your asset pipeline, and your pages stay lean. For more on getting images web-ready, see our guides on compressing images for the web, optimizing images for the web, the best image format for websites, converting SVG to PNG, and converting PNG to WebP.

Ready to compress your files? Join thousands of creators using Compresto ⚡