Base64 image data URIs
A data URI saves one request and costs about a third in size — plus the ability to cache the image separately from the page around it. That second cost is the one people forget.
By the Withuse team · Updated
The anatomy, and the overhead
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
└──┬──┘└───┬────┘└─┬──┘└──────────┬──────────┘
scheme MIME encoding the payload
1×1 PNG: 70 bytes raw
96 Base64 characters (1.37×)
118 characters total (+22 for the prefix)The prefix is fixed, so it dominates for tiny assets and vanishes for large ones. The encoding ratio settles near 1.33 as the payload grows:
1 KB image -> ~1.3 KB data URI 10 KB image -> ~13.3 KB 100 KB image -> ~133.3 KB
Gzip recovers less of this than intuition suggests. Base64 output has already destroyed the byte-level patterns a compressor looks for, and the image formats underneath — PNG, JPEG, WebP — are compressed already. You are adding a third to something that will not give it back.
The cost that is not size
A data URI has no URL, and therefore no cache entry. It cannot be fetched conditionally, cannot have its own expiry, and cannot be shared between pages. It lives and dies with whatever document contains it.
In a stylesheet that means every visitor re-downloads the image whenever that stylesheet changes for any unrelated reason — a colour tweak elsewhere invalidates your logo. In HTML it means the bytes arrive with every page view, since HTML is rarely cached aggressively. A separate file is fetched once and reused across pages and deploys until its content actually changes.
There is a second-order effect worth noting. Because the encoded image lives inside a text file, it inflates whatever build artefact contains it — a CSS bundle with several embedded icons grows by their combined encoded size, and that bundle is usually render-blocking. The bytes you moved out of a parallel image request landed in the critical path instead.
Where the line falls
| Asset | Verdict | Why |
|---|---|---|
| 1×1 placeholder | ✅ data URI | the request costs more than the bytes |
| Tiny icon, under ~1KB | ✅ data URI | if it changes with the document anyway |
| Icon of any complexity | ⚠️ inline SVG | smaller, scales, styleable by CSS |
| Logo, illustration | ❌ separate file | cacheable, parallel, independently versioned |
| Photograph | ❌ separate file | responsive sizes, lazy loading, modern formats |
SVG usually wins the cases people reach for
The assets most often turned into data URIs are icons, and for those an SVG is generally the better answer twice over. It is text, so it compresses well and often ends up smaller than the Base64 of an equivalent PNG. And it can be inlined as markup rather than as an encoded string, which skips the Base64 layer entirely — no third of overhead, and CSS can restyle it with currentColor.
Photographs are the real exception, since SVG cannot represent them. There the choice is genuinely between a data URI and a file, and above a kilobyte the file wins on every axis that matters.
Two limits worth knowing
Data URIs embedded in HTML or CSS are parsed before the page can render, so a large one delays first paint rather than loading in parallel like an image request would. And a Content Security Policy whose img-src omits data: will refuse them outright — worth checking before adopting the pattern, since the failure looks like a broken image rather than a policy error.
Frequently asked questions
How much larger does Base64 make an image?
About a third, plus a fixed prefix. We measured a 1×1 PNG at 70 bytes raw and 96 Base64 characters, and the full data URI at 118 characters once data:image/png;base64, is prepended — that scheme and MIME prefix costs 22 characters regardless of image size. At useful sizes the ratio settles near 1.33, so a 10KB image becomes roughly 13.3KB and a 100KB image roughly 133KB. Gzip recovers less of this than people expect, because Base64 output has already lost the byte patterns a compressor exploits, and image formats are compressed to begin with. Expect to keep most of the third you added rather than compressing it away at the transport layer. Budget for the encoded size, not the original, when deciding whether an asset fits inline.
When is a data URI worth it?
When the asset is small enough that the request itself costs more than the bytes, and it will not change independently of the document. A one-pixel placeholder, a tiny inline icon, a low-quality image placeholder blurred behind a real photo — all reasonable. Under about a kilobyte is a defensible line. Above that the trade inverts: a separate file can be cached, served in parallel, and replaced without invalidating the page around it, while an embedded copy is re-downloaded with the document every single time it changes, and it changes whenever anything else in that document does, so an unrelated edit re-sends the image to every visitor who returns.
Do data URIs get cached?
Only as part of whatever document contains them, which is the cost people usually miss. A data URI has no URL of its own, so no cache entry, no separate expiry and no conditional request. Embed a logo in your CSS and every visitor downloads it again whenever that stylesheet changes for any unrelated reason. Embed it in HTML and it arrives with every page view, because HTML is typically not cached aggressively. A normal image file, by contrast, is fetched once and reused across pages and releases until its content actually changes, which is the behaviour you want for anything a visitor sees more than once, across pages or across visits.
Should I use SVG instead of a Base64 raster?
For icons and simple graphics, almost always. An SVG is text, so it usually compresses smaller than the equivalent Base64-encoded PNG, and it stays sharp at any resolution rather than needing a second file for high-density displays. It can also be inlined directly into HTML as markup, with no Base64 layer at all, which removes the third of overhead entirely and lets CSS style it. The exception is photographic content, which SVG cannot represent — there you are choosing between a data URI and a separate file, and above a kilobyte the separate file wins on caching, parallel loading and the ability to serve modern formats to browsers that support them. For anything vector-shaped, inlining the SVG markup skips the encoding layer altogether.
Are there size limits on data URIs?
No formal limit in the data URL specification, but practical ceilings appear well before that. Browsers historically capped data URIs in the low megabytes, and anything embedded in a stylesheet or HTML document blocks rendering while it is parsed, so a large one delays first paint rather than loading alongside the page. Some email clients strip them entirely, and Content Security Policy directives that omit data: will refuse to load them at all. Treat anything beyond a few kilobytes as a signal that the asset wants its own URL, where it can be cached, versioned and replaced independently of the document that references it, which is what caching was for.
References
Encode a file with the Base64 encoder, or compare the encodings in Base64 vs hex. More tools at withuse.io/tools.