Developer FIELD NOTES · 4 MIN READ
Data URIs Explained: Inlining Images as Base64
The data URI anatomy, the one-third Base64 size cost, when inlining beats a separate file, and how to decode a URI back into bytes.
Somewhere in a stylesheet you have seen it: an src attribute hundreds of characters long, starting with data:image/png;base64, and ending in a wall of letters. That is a data URI — an entire image file folded into a line of text. This article walks through what that string is made of, where it helps, what it costs, and how to turn it back into bytes.
The anatomy of a data URI
A data URI has three parts separated by punctuation: the scheme data:, the media type (MIME type), and the payload after a comma. With Base64 the middle also carries the ;base64 flag:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ…
└─┬─┘ └───┬────┘ └──┬──┘ └────────────────┬────────────────┘
scheme MIME type flag Base64 payload
Run a real file through and the numbers are concrete. A minimal 1×1 PNG is 70 bytes on disk. Base64 expands it to 96 characters, and the 22-character prefix data:image/png;base64, sits in front, so the full data URI is 118 characters. That is the whole story: prefix, then the encoded bytes — nothing compressed, nothing hidden.
Where inlining pays off
Because the bytes live inside the document itself, a data URI needs zero extra network requests. The browser never opens a second connection, waits on DNS, or risks a 404 for a missing file. That makes inlining attractive for:
- tiny icons and UI chrome inside HTML
<img src>tags, - background textures and decorative images in CSS
url(...)values, - favicons declared with
<link rel="icon" href="data:...">, - self-contained files that must work offline — email templates and single-file HTML documents.
The payload also can't get out of sync with the page: whatever is in the HTML is exactly what renders.
The cost: inflation and caching
Base64 carries roughly 6 bits of data per 8-bit character, so the payload grows by about 4/3 — one third bigger than the file. (The 3-bytes-to-4-characters math behind that number is unpacked in How Base64 Encoding Works.) On top of the payload, the prefix adds a fixed cost that only matters for very small files — our 70-byte PNG grew to 118 characters, a 1.69× total, while a 100 KB image settles near 1.34×.
The subtler cost is caching. A separate logo.png is downloaded once and reused by every page that references it. A data URI has no independent identity: the same bytes embedded in ten pages are transferred ten times, and they make every one of those pages heavier. The working rule of thumb: inline small, page-specific assets; link anything reused or large.
Reading the string back into bytes
Decoding reverses the walk. The decoder splits off the prefix to recover the MIME type, strips any whitespace from the payload, and requires the Base64 length to be a multiple of 4 — the = padding characters at the end are part of that contract. Then every four characters convert back into three bytes.
Two input shapes behave differently, and both are worth knowing. A full data URI like data:image/png;base64,iVBOR… decodes to bytes labeled image/png. A bare Base64 string with no data: prefix is rejected — the tool needs the URI shape to know what it is decoding. And a data URI without the ;base64 flag, such as data:text/plain,hello, carries its payload as plain text: it decodes to the five bytes of the word "hello" with type text/plain.
Reading the first characters like a fingerprint
Because the first bytes of a file format are fixed, the first Base64 characters become a tell. Every PNG begins with the bytes 89 50 4E 47, so its data URI always starts iVBOR; every JPEG starts FF D8 FF, which always encodes as /9j/. If a pasted URI starts with anything else, the contents may not match the declared type — a quick way to spot a renamed file before anything breaks.
Try it yourself
Convert an image to a data URI (or decode one back to bytes) with the Image Base64 Encoder — a 1×1 PNG is a great first test, since 70 bytes should produce a 118-character URI. For plain text instead of files, the Base64 Encoder & Decoder encodes strings in both directions, and the Hex Encoder & Decoder shows the same bytes as two-digit hex pairs, which makes file signatures like 89 50 4E 47 easy to eyeball. Encoding a whole list of strings at once? The Base64 Batch tool processes them in one pass.