Base64 image data URIs are one of those web techniques that look like a magic shortcut the first time you use them.
Instead of referencing an external file:
<img src="/logo.png" alt="Logo">
you can put the image bytes directly in the document as text:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="Logo">
That can be useful. It can also make a page slower, harder to cache, and more annoying to maintain.
Here is the practical rule: inline images as Base64 when self-containment matters more than caching. Keep normal image files when the browser should be able to cache, resize, lazy-load, or optimize them independently.
What a Base64 image actually is
An image file is binary data. Base64 rewrites that binary data as plain text using a limited character set. To make the browser treat the text as an image, you wrap it in a data URI:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
The first part tells the browser the MIME type. The second part tells it the data is Base64 encoded. The long tail is the image itself.
Base64 is not compression. It is not encryption. It is just a text representation of the same bytes.
When inlining an image is worth it
1. Tiny icons and UI assets
For very small images, removing an extra HTTP request can be worth the extra bytes. This is especially true for small icons, logos, placeholders, simple UI sprites, or tiny transparent PNGs.
Modern HTTP/2 and HTTP/3 make extra requests cheaper than they used to be, so this is not an automatic win. But for a one-off tiny asset inside a small page or widget, a data URI can still be a clean choice.
2. Single-file deliverables
Sometimes the point is not raw page speed. Sometimes you need one file that carries everything with it:
- an HTML report
- an email template
- a CodePen or demo snippet
- a CMS block where you cannot upload assets
- a test fixture that should not depend on external hosting
In those cases, Base64 is useful because the image travels with the HTML, CSS, JSON, or JavaScript.
3. Prototypes and throwaway snippets
If you are testing a layout, writing a bug reproduction, or pasting a minimal example into a ticket, a data URI can save time. You do not need to set up static hosting just to show one image.
4. Local-only conversion workflows
If the image is private, it is nice to avoid uploading it to a random converter. Browser APIs can generate a Base64 data URI locally, so the file never leaves your device.
When you should not inline the image
1. Large photos and hero images
Base64 usually makes the encoded data about 33% larger than the original binary file. That is because Base64 stores every 3 bytes as 4 text characters.
For a large JPG, PNG, or WebP, that extra size is not a rounding error. Keep big images as normal files.
2. Images reused across pages
An external image can be cached once and reused across page views. An inlined image is bundled into every document or stylesheet that contains it.
If the same logo appears on 20 pages, inlining it 20 times is usually worse than letting the browser cache one file.
3. Responsive images
Normal image files can use srcset, sizes, lazy loading, CDN transforms, format negotiation, and caching headers.
<img
src="/hero-800.webp"
srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1600.webp 1600w"
sizes="100vw"
loading="lazy"
alt="Product screenshot"
>
That is much harder to preserve when the image is baked into a string.
4. Anything you expect humans to edit
Base64 strings are unpleasant to review in Git diffs, easy to truncate by accident, and noisy inside templates. If designers, marketers, or other engineers need to update the image regularly, use a normal asset file.
How to generate a Base64 data URI in the browser
The simplest browser-native path is FileReader.readAsDataURL().
<input id="file" type="file" accept="image/*">
<textarea id="output" readonly></textarea>
<script>
const fileInput = document.querySelector("#file");
const output = document.querySelector("#output");
fileInput.addEventListener("change", () => {
const file = fileInput.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
output.value = reader.result;
};
reader.readAsDataURL(file);
});
</script>
The result will look like this:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...
You can use that string directly in HTML:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="Logo">
or in CSS:
.logo {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...");
}
A simple checklist
Inline the image if:
- it is small
- it is not reused across many pages
- self-contained delivery matters
- you do not need responsive image behavior
- the string will not make your source files painful to maintain
Keep it as a normal file if:
- it is a photo or large graphic
- it should be cached separately
- it appears on many pages
- it needs
srcset, lazy loading, CDN resizing, or image optimization - non-developers need to replace it often
Tiny tool note
I built a small free tool for this workflow: PNG to Base64 converter. It runs entirely in the browser with FileReader, so the PNG is not uploaded, and it gives you the raw Base64 string plus ready-to-paste HTML and CSS snippets.
There is also a general image to Base64 converter for JPG, SVG, WebP, GIF, and other image formats.
Use Base64 as a packaging tool, not a default image strategy. When the image is tiny or the deliverable must be self-contained, it can be perfect. When performance, caching, and responsive delivery matter, boring old image files are still the better answer.
Top comments (0)