What Is a Data URI?
A data URI (also called a data URL) lets you embed a file — an image, font, SVG, or any binary asset — directly into a web page as a base64-encoded text string, instead of referencing an external file by URL. You have probably seen one: they start with data: and look something like this:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
That entire string can go anywhere a URL normally goes — an <img> src, a CSS background-image, a <link> href for a font, or an anchor href for a downloadable file. No HTTP request is made; the browser decodes the string in place.
The Data URI Format
Every data URI follows this structure:
data:[<mediatype>][;base64],<data>
| Part | Example | Meaning |
|---|---|---|
data: |
data: |
Scheme — tells the browser this is inline data |
<mediatype> |
image/png |
MIME type of the content (defaults to text/plain;charset=US-ASCII if omitted) |
;base64 |
;base64 |
Encoding flag — omit for plain text, include for binary |
,<data> |
,iVBOR… |
The actual content (base64-encoded if ;base64 is present, percent-encoded otherwise) |
Plain-text example (no base64 needed)
<a href="data:text/plain,Hello%20world">Download text file</a>
Binary image example (base64 required)
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="1px red dot" width="1" height="1">
SVG example (can stay as percent-encoded text)
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Ccircle cx='50' cy='50' r='50' fill='red'/%3E%3C/svg%3E" alt="red circle">
SVG is often cleaner without base64 because the XML is human-readable once decoded.
How to Create a Data URI
JavaScript (browser)
// From a File or Blob (e.g., user-uploaded image)
function fileToDataUri(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file); // produces "data:image/png;base64,..."
});
}
// Usage
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const uri = await fileToDataUri(e.target.files[0]);
document.querySelector('img').src = uri;
});
// From a URL (Node.js / fetch)
const res = await fetch('https://example.com/logo.png');
const buf = Buffer.from(await res.arrayBuffer());
const dataUri = `data:image/png;base64,${buf.toString('base64')}`;
Python
import base64
import mimetypes
from pathlib import Path
def file_to_data_uri(path: str) -> str:
p = Path(path)
mime, _ = mimetypes.guess_type(p)
mime = mime or "application/octet-stream"
encoded = base64.b64encode(p.read_bytes()).decode()
return f"data:{mime};base64,{encoded}"
uri = file_to_data_uri("logo.png")
# → "data:image/png;base64,iVBORw0KGgo..."
Go
package main
import (
"encoding/base64"
"fmt"
"mime"
"os"
"path/filepath"
)
func fileToDataURI(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", err
}
ext := filepath.Ext(path)
mimeType := mime.TypeByExtension(ext)
if mimeType == "" {
mimeType = "application/octet-stream"
}
encoded := base64.StdEncoding.EncodeToString(data)
return fmt.Sprintf("data:%s;base64,%s", mimeType, encoded), nil
}
PHP
function fileToDataUri(string $path): string {
$data = file_get_contents($path);
if ($data === false) {
throw new RuntimeException("Cannot read: $path");
}
$mime = mime_content_type($path) ?: 'application/octet-stream';
$encoded = base64_encode($data);
return "data:$mime;base64,$encoded";
}
$uri = fileToDataUri('logo.png');
// → "data:image/png;base64,iVBOR..."
When to Use Data URIs
Good use cases
| Use case | Why data URIs work well |
|---|---|
| Small icons and logos in HTML email | Email clients block external images; inline base64 always loads |
| Critical above-the-fold images in static HTML | Zero HTTP round-trip, guaranteed availability |
| SVG icons in CSS | Eliminates a separate asset request for a tiny file |
| Downloadable blobs generated in the browser | <a href="data:…" download="file.csv"> triggers download without a server |
Favicons embedded in <link> |
Single-file HTML pages that must be fully self-contained |
Bad use cases
| Use case | Problem |
|---|---|
| Large images (> ~5 KB) | Base64 inflates size by ~33 %; plus the browser can't cache the URI separately |
| Images reused on multiple pages | A normal URL is cached once; each page with a data URI re-downloads the encoded string |
| Performance-critical pages | Data URIs block HTML parsing; a normal <img> is loaded asynchronously |
| Logos with many breakpoints | Responsive images (srcset) don't work with data URIs |
The rule of thumb: data URIs make sense when the file is small and either unique to the page or must be self-contained (email, offline HTML).
Data URI Size Limits
Browsers do not enforce a universal limit, but practical ceilings exist:
| Context | Effective limit |
|---|---|
All modern browsers (img, CSS) |
2 MB–32 MB (varies by browser) |
| Internet Explorer 8 | 32 KB (long obsolete but worth knowing) |
| URL bar / navigation | ~2 KB on most browsers |
| HTML email clients | Varies; some reject data URIs entirely |
For typical use, anything under a few hundred kilobytes works reliably. Beyond that, prefer a normal URL.
Data URI vs URL vs Blob URL
| Feature | Data URI | File URL | Blob URL |
|---|---|---|---|
| Created | Statically embedded | External file on disk or server | URL.createObjectURL(blob) in JS |
| HTTP request | None | Yes (server) or No (local) | None |
| Browser cache | Not cacheable as a URL | Yes | Not cacheable across sessions |
| Size overhead | +33 % (base64) | None | None |
| Lifetime | Permanent in HTML | While server is up | Until URL.revokeObjectURL() |
| Best for | Self-contained pages, email | Most web assets | Temporary in-browser previews |
For in-browser image previews (e.g., before upload), a Blob URL (URL.createObjectURL) is faster to create and uses no extra memory for encoding — prefer it over FileReader.readAsDataURL when you only need a temporary src.
Quick Reference
# Full syntax
data:[mediatype][;charset=<charset>][;base64],<data>
# Common MIME types
data:image/png;base64,…
data:image/jpeg;base64,…
data:image/svg+xml,… ← SVG can stay percent-encoded
data:image/gif;base64,…
data:image/webp;base64,…
data:text/plain;charset=utf-8,Hello
data:text/html,<h1>Hello</h1>
data:application/json,{"key":"value"}
data:font/woff2;base64,…
data:application/pdf;base64,…
# Inline CSS background
background-image: url("data:image/png;base64,…");
# Downloadable link
<a href="data:text/csv;charset=utf-8,name%2Cage%0AAlice%2C30" download="data.csv">Download CSV</a>
Common Pitfalls
1. Forgetting ;base64 for binary files
Binary data without the ;base64 flag is interpreted as percent-encoded text. The result will be garbled or a parser error.
2. Using data URIs for large images A 100 KB PNG becomes a 133 KB base64 string — and can't be cached separately. Every page load re-parses it. Use a real URL for anything larger than a small icon.
3. Embedding data URIs in HTML email
Some email clients (notably Gmail) strip <img> data URIs citing security policy. SVG data URIs are often blocked entirely. Test with your target clients.
4. Assuming they're safe for user-supplied content
Never construct a data URI from untrusted content without sanitization — data:text/html,<script>…</script> executes JavaScript in older browsers. Modern browsers restrict this for security, but the safest approach is to avoid text/html data URIs with user content entirely.
5. Confusing data URIs with Blob URLs
blob:https://example.com/… looks similar but is a temporary in-memory reference, not inline data. They behave differently in caching, serialization, and across page loads.
6. SVG data URIs with unescaped characters
SVG strings containing <, >, ", or # must be percent-encoded (or base64-encoded) before embedding. Unescaped characters break the URL parser.
FAQ
What is the difference between a data URI and a data URL?
The terms are interchangeable. Officially they are URIs (Uniform Resource Identifiers); developers commonly call them data URLs because they are used in places that normally take a URL.
Does base64 encoding make data URIs secure?
No. Base64 is encoding, not encryption. Anyone can decode the string to recover the original file instantly. Do not embed secrets in data URIs.
Can I use a data URI as an href in an anchor tag?
Yes — and it's one of the most useful patterns. Set the download attribute to trigger a save dialog: <a href="data:text/csv,…" download="export.csv">Download</a>. The file is generated entirely in the browser without a server request.
Are data URIs blocked by Content Security Policy?
They can be. img-src 'self' data: must be present in your CSP to allow data URIs in <img> tags. Stricter policies that omit data: will silently block them. Check your CSP header if data URIs stop loading in production.
What MIME type should I use for a binary file I don't recognize?
application/octet-stream — the generic binary fallback. Browsers will treat it as a download rather than attempting to render it.
Can I use a data URI for a CSS @font-face?
Yes. Embedding fonts as data URIs eliminates the font request and avoids flash-of-unstyled-text (FOUT). The trade-off is page size: a typical variable font can be 100–300 KB, adding significant base64 overhead. Only worthwhile for tiny subsetted fonts used on every page.