ToolKitSphere IconToolKitSphere
Image Tools

What Are Data URIs? Base64 Images Explained

Online Tools Platform Team8 min read

Most images on the web live in their own file and arrive over their own network request. A base64 image does something different: it takes the raw bytes of a PNG, JPEG or SVG and rewrites them as ordinary text that can be pasted straight into an HTML attribute, a stylesheet, or a JSON payload. No file, no request, no separate URL. That trick is occasionally exactly what you need and much more often a performance mistake, and the difference comes down almost entirely to file size. For where this fits among the broader format decisions, see The Complete Guide to Web Image Formats.

This post covers what base64 actually does to your bytes, how the data: URI syntax is put together, and the specific circumstances where embedding an image beats linking to it.

What Base64 Encoding Actually Does

Base64 solves a problem that has nothing to do with images. It converts arbitrary binary data into a 64-character alphabet — A–Z, a–z, 0–9, + and /, with = as padding — that survives being passed through systems designed for text. Email bodies, URLs, XML attributes, JSON strings and CSS declarations are all text channels, and raw binary bytes either break them or get silently mangled.

The mechanism is simple arithmetic. The encoder takes 3 bytes of input — 24 bits — and slices them into four 6-bit groups. Each 6-bit group indexes one character in the 64-character alphabet. So 3 bytes in, 4 characters out.

That ratio is the entire story of base64's cost. Four characters occupy four bytes of text, so the encoded output is 4/3 the size of the input: an unavoidable ~33% inflation. A 30KB PNG becomes roughly 40KB of text. If the input length is not a multiple of three, one or two = characters pad the final group. There is no efficient variant and no setting that avoids this — the overhead is structural.

One partial reprieve: base64 output is repetitive ASCII, so gzip and Brotli compress it reasonably well — a compressed payload often lands within 5–15% of the compressed original rather than a full 33% above it. But the browser still decodes the full inflated string in memory, and the original file would have been compressed too.

The Data URI Syntax

A data URI is the wrapper that makes an encoded blob usable as if it were a URL. The full shape is:

data:[<media type>][;charset=<charset>][;base64],<data>

Broken into parts:

  • data: — the scheme, in the same slot where you would normally write https:
  • image/png — the media (MIME) type, telling the browser how to interpret the payload
  • ;base64 — a flag saying the payload is base64-encoded rather than URL-encoded plain text
  • , — the separator
  • iVBORw0KGgoAAAANSUhEUg… — the payload itself

In practice, an inline PNG looks like this:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB…" alt="Status dot" width="16" height="16">

And in CSS, which is where data URIs are most commonly useful:

.icon-check {
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0…");
}

Two details matter. First, ;base64 is optional — omit it and the payload is treated as URL-encoded text. For SVG, which is already text, that is usually the better choice: URL-encoding the markup avoids the 33% penalty entirely, often produces a shorter string, and stays readable enough to tweak a fill colour without re-encoding. Second, get the media type right — a JPEG labelled image/png fails to render in some contexts even though the bytes are valid.

To produce these strings, the Image to Base64 String Converter takes a file and returns both the raw encoded string and a ready-to-paste data: URI with the correct media type already filled in. Everything is encoded in your browser using the local FileReader API — the image is never uploaded anywhere, which matters when the asset is an unreleased logo or a screenshot containing customer data. To go the other direction — inspecting a data URI you found in someone's stylesheet or a debugging payload — the Base64 to Image Preview & Downloader decodes and renders it locally.

The Real Costs of Inlining

The 33% inflation is the obvious cost. The others matter more.

Caching disappears. A linked image file gets its own cache entry with its own lifetime and its own ETag. An embedded image is part of the document or stylesheet it lives in, so it has no independent existence. Change a single colour in your CSS and every embedded image in that file is re-downloaded. Use the same icon on five pages of a server-rendered site and it is downloaded five times.

It blocks rendering. CSS is a render-blocking resource. Every kilobyte of base64 you add to a stylesheet delays the point at which the browser can paint anything at all. A 200KB inlined hero image does not "save a request" — it holds up First Contentful Paint for the whole page.

You lose modern image delivery. An embedded image cannot be lazy-loaded, cannot participate in srcset for responsive sizes, cannot be served as WebP to browsers that support it and JPEG to those that do not, and cannot be swapped for a next-gen format later without editing your source. Those capabilities are worth far more than one saved request — see WebP vs PNG vs JPG for what you give up.

The original argument has expired. Data URIs became popular when HTTP/1.1 limited browsers to about six parallel connections per host and every request carried real handshake cost. Under HTTP/2 and HTTP/3, requests are multiplexed over one connection and an additional small file is close to free. The problem inlining was invented to solve mostly no longer exists.

When Inlining Is Genuinely Right

None of that makes data URIs useless. There are four cases where they win cleanly.

Tiny critical-path assets. An icon, a gradient, a 1–2KB background image referenced by critical CSS that must render in the very first paint. Here the saved round trip beats the extra bytes, because the bytes are trivial and the request is on the critical path.

Self-contained documents. A single-file HTML report, a downloadable dashboard export, an offline document. When the file must work with no accompanying assets, embedding is the only option and size is a secondary concern.

Generated and ephemeral images. A canvas export, a QR code, a chart the user just built, a cropped avatar preview before upload. canvas.toDataURL() hands you a data URI directly and there is no file to link to yet.

Dynamic SVG. Small SVG icons recoloured per theme, embedded URL-encoded (not base64) in CSS custom properties. This is the one case where inlining is often both smaller and more maintainable than separate files.

A workable threshold: inline under 2KB, link everything above 4KB, and measure in between. Below 2KB the request overhead dominates; above 4KB the inflation and cache loss dominate. And "measure" means checking your actual Largest Contentful Paint before and after, not just counting requests.

Practical Notes

Keep encoded strings out of hand-maintained source. A 40KB unbroken line of base64 makes every diff useless. Generate data URIs at build time, or keep them in a CSS file nobody edits by hand. If you have inherited a stylesheet full of embedded assets, running it through the CSS Formatter & Beautifier at least makes the surrounding rules navigable.

Optimise before you encode. Base64 has no compression of its own — it faithfully inflates whatever you feed it. A 33% penalty on an already-optimised 1.2KB icon is 400 bytes; the same penalty on an unoptimised 400KB PNG is 130KB.

Remember base64 is not encryption. It is a reversible transport encoding with no key and no secrecy. Anyone can decode it instantly — that is the whole point of tools like the Base64 Encoder / Decoder. Never treat an encoded payload as hidden.

The Short Version

Base64 turns binary image data into text at a fixed cost of about 33% more bytes, and a data URI wraps that text with a media type so the browser can render it in place of a URL. It removes one network request and gives up independent caching, lazy loading, responsive sizing, format negotiation, and a share of your render-blocking budget in return.

That trade is worth taking for one- or two-kilobyte assets on the critical path and for documents that must stand alone. For anything larger — certainly for photographs — a properly compressed file in a modern format wins on every axis. If you are choosing that format now, AVIF vs WebP covers where the next-generation options stand.

Frequently asked questions

What is a base64 image?

A base64 image is an image file whose binary bytes have been re-expressed as plain ASCII text using the base64 alphabet. Because it is text, it can be pasted directly into HTML, CSS, JSON or an email template instead of being referenced as a separate file over the network.

Does base64 encoding make images bigger?

Yes. Base64 represents every 3 bytes of binary data as 4 ASCII characters, so the encoded string is about 33% larger than the original file, plus a few bytes of prefix. Compression such as gzip or Brotli recovers some of that on the wire, but never all of it.

What is the syntax of a data URI?

A data URI looks like data:[<media type>][;base64],<data>. For an image that is typically data:image/png;base64, followed by the encoded string — for example data:image/png;base64,iVBORw0KGgo… The media type tells the browser how to decode the payload.

When should I use a base64 image instead of a file?

Only for very small, render-critical assets — icons and background images of roughly 1–2KB inside critical CSS — or for self-contained documents such as single-file HTML exports and email templates where external image references are unreliable or blocked.

Why are base64 images bad for performance on large photos?

A large embedded image inflates the HTML or CSS file it lives in by 33%, blocks that render-critical resource from finishing, cannot be cached or revalidated on its own, and cannot be lazy-loaded or served responsively. A normal image file avoids all four problems.

Can browsers cache base64 data URIs?

Not independently. The image is part of the document or stylesheet, so it is only cached as part of that file. Change one line of CSS and the whole embedded payload is re-downloaded, and the same image embedded on five pages is downloaded five times.

How do I embed an image in CSS?

Encode the image to base64, then use it as a background image: background-image: url("data:image/svg+xml;base64,PHN2Zy…"). For SVG you can also skip base64 entirely and use URL-encoded markup, which is usually smaller than the base64 form.

Try the related tools

Related articles