tooldura

Developer Tools

Base64 Images: The 33% Overhead Explained, and When It's Worth It

T
tooldura editorial
7 min readUpdated August 22, 2026Open tool →

A 3 KB icon becomes a 4 KB string the moment you base64-encode it. That is not a rounding error or a bad encoder, it is what the format does by definition, and it is the number every guide about inlining images skips past on the way to the part where it looks convenient.

Why It Is Always 33%, Not Roughly 33%

Base64 exists to move binary data through channels that only trust text: 1970s mail transports, JSON, CSS, HTML attributes. None of those can carry an arbitrary byte, so base64 re-spells the data using only 64 printable characters, defined in RFC 4648.

The mechanism is fixed, not tunable: three input bytes are read as 24 bits, and those 24 bits are cut into four 6-bit groups, each one mapped to one of the 64 printable characters (A-Z, a-z, 0-9, + and /). Three bytes in, four characters out, every time. That ratio, 4 divided by 3, is exactly 1.333, which is where the 33% comes from. Encoding a length that is not a multiple of three pads the last group with one or two = characters, which only ever adds a byte or two, not a meaningful amount.

There is no better base64 encoder that avoids this. The overhead is the cost of using 6 bits of every 8-bit character to carry information, and the other 2 bits to stay inside the printable-ASCII range every one of those old text channels could survive.

What a Few Common Sizes Actually Become

Exact 4/3 growth before padding; real files round to the nearest multiple of 4 characters.

Original fileBase64 outputGrowth
1 KB1.33 KB+33%
4 KB5.33 KB+33%
50 KB66.7 KB+33%
500 KB667 KB+33%

Where the Trade Actually Pays Off

The 33% is not the only cost, and it is not always the deciding one. What a data URI buys back is one fewer HTTP request, and for a genuinely tiny image, that request was the expensive part: even over HTTP/2, a request still costs a round trip's worth of latency and a slice of the browser's connection budget.

Most build tooling has already settled on where that trade stops paying off. Vite's `assetsInlineLimit` defaults to 4096 bytes, and webpack's `url-loader`, which originated the pattern, shipped with the same 4 KB default. Below that line, an asset is inlined as a data URI automatically; above it, it stays a separate file. That number was not picked at random, it is the point where the community consensus lands, and it is the threshold this site's own Image to Base64 tool warns past.

For an icon, a 1x1 tracking pixel, or a tiny placeholder blurred into an image's own CSS, inlining is close to free and saves a request outright. For anything a normal camera or a stock photo site would produce, the 33% and the caching cost below outweigh the one request saved.

📭

The email client that ignores it entirely

Base64 images are commonly recommended for HTML email, since inline images survive being forwarded and don't break when hosted images get blocked by a mail client. The catch: classic Outlook for Windows (2007 and every version since) renders HTML mail with Microsoft Word's layout engine rather than a browser engine, and Word has never supported the data: URI scheme. The image simply does not appear, with no error and no fallback, in one of the most widely deployed corporate mail clients. The reliable option for email is a real attachment referenced by a cid: URI, not base64.

The Cost That Does Not Show Up in File Size

A separate image file has a URL, and a URL is the unit browser caching works on. Request logo.png once and, with reasonable cache headers, every later page load reuses the copy already on disk, even after the user closes the tab and comes back tomorrow.

A data URI has no URL. It is a string embedded inside whatever CSS or HTML file contains it, so it is only ever as cacheable as that surrounding file. If the CSS changes for any reason, unrelated to the image, the browser re-downloads and re-decodes the image too, because from the cache's point of view it never existed as its own resource. Inline ten images this way into one stylesheet and the whole stylesheet is invalidated whenever any one of them, or anything else in the file, changes.

This is the cost the file-size number never shows, and it is usually the bigger one on a page that gets more than one visit.

See the exact overhead on your own image

Base64, a data URI, and ready CSS and HTML snippets, with the real byte count before you commit to any of them.

Open Image to Base64 →

A Short List of When to Reach for Each Option

The 4 KB line is a default, not a law. These are the situations that actually move it.

1

Inline it: a tiny, one-off, rarely-changing icon

Under a few KB, used in one place, not swapped often. The saved request is worth more than the 33% and the lost cache entry.

2

Keep it a file: anything a camera or designer produced

Photographs and full illustrations are already well past the point where 33% is a meaningful number of bytes, and they benefit the most from independent caching across repeat visits.

3

Inline it: a placeholder meant to be replaced by JavaScript

A 1x1 transparent pixel or a blurred low-resolution stand-in that swaps out on load has no long-term caching value anyway, so the request saved is pure upside.

4

Keep it a file: anything going into an email

Given how unevenly mail clients support data URIs, a real attachment with a cid: reference is the only version that is guaranteed to render everywhere.

5

Keep it a file: an image reused across many pages

Every page that inlines the same icon pays the 33% overhead again and gets none of the benefit a shared, cached file would give the second and third visit.

Frequently Asked Questions

Related Tools

Keep Reading