Blob URLs are temporary URLs that reference in-memory binary data in the browser. They're essential for file downloads, image previews, and media playback.
Unlike data URLs that embed content directly, blob URLs are references to binary data stored in browser memory. This makes them more efficient for large files—you're not duplicating the content in the URL string. They're the foundation for features like file downloads, image previews, and media recording.
Key Takeaways
- 1Blob URLs reference in-memory Blob objects
- 2Created with URL.createObjectURL()
- 3Must be revoked to free memory
- 4Only valid in the current session/origin
- 5Not shareable or persistent
"A Blob URL is a URL that refers to a Blob or File object. Blob URLs are created and revoked using static methods on the URL object. They are only valid within the context that created them."
Blob URL Structure
Blob URLs look like regular URLs but contain a UUID that references data in browser memory. The origin component ensures blob URLs are scoped to the page that created them.
# Blob URL format
blob:origin/uuid
# Examples:
blob:https://example.com/550e8400-e29b-41d4-a716-446655440000
blob:null/550e8400-e29b-41d4-a716-446655440000
# Components:
blob: - Scheme
https://example.com - Origin (or null for local files)
/uuid - Unique identifier
# Note: The UUID is browser-generated
# The URL only works within the same origin that created itThe UUID is randomly generated each time you create a blob URL—even for the same content. Because blob URLs include the origin, they can't be used cross-domain, which provides security but limits sharing.
Let's look at the different ways to create blob URLs from various data sources.
Creating Blob URLs
The URL.createObjectURL() method generates a blob URL from any Blob or File object. These examples show how to create blob URLs from different sources: raw data, file inputs, canvas elements, and fetch responses.
// Create Blob URL from Blob
const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
const blobUrl = URL.createObjectURL(blob);
console.log(blobUrl);
// blob:https://example.com/550e8400-e29b-41d4-a716-446655440000
// Create from File object
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
const fileUrl = URL.createObjectURL(file);
// Use for preview
const img = document.createElement('img');
img.src = fileUrl;
document.body.appendChild(img);
});
// Create from canvas
canvas.toBlob((blob) => {
const canvasUrl = URL.createObjectURL(blob);
// Use canvasUrl
}, 'image/png');
// Create from fetch response
const response = await fetch('/api/file');
const blob = await response.blob();
const downloadUrl = URL.createObjectURL(blob);Each blob URL creates a reference that keeps the underlying data in memory. The canvas example shows how to generate downloadable images, while the fetch example demonstrates downloading files for offline access or processing.
Because blob URLs consume memory, you must revoke them when you're done. This is a common source of memory leaks in web applications.
Revoking Blob URLs
Calling URL.revokeObjectURL() releases the memory held by a blob URL. Forgetting to revoke blob URLs is one of the most common memory leaks in JavaScript applications, especially in image-heavy interfaces.
// IMPORTANT: Always revoke blob URLs to free memory
// Basic revocation
const blobUrl = URL.createObjectURL(blob);
// ... use blobUrl ...
URL.revokeObjectURL(blobUrl);
// Revoke after image loads
const img = new Image();
img.src = URL.createObjectURL(blob);
img.onload = () => {
URL.revokeObjectURL(img.src);
};
// Revoke after download
function downloadBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
// Revoke after click
setTimeout(() => URL.revokeObjectURL(url), 100);
}
// Track and revoke all blob URLs
const blobUrls = [];
function createTrackedBlobUrl(blob) {
const url = URL.createObjectURL(blob);
blobUrls.push(url);
return url;
}
function revokeAllBlobUrls() {
blobUrls.forEach(url => URL.revokeObjectURL(url));
blobUrls.length = 0;
}The key insight is timing: revoke after the resource is loaded (like in onload) or after the user action completes (like the download click). The tracking pattern at the end is useful for cleanup during component unmounting or page navigation.
Now let's explore the most common scenarios where blob URLs provide the best solution.
Common Use Cases
Blob URLs excel in scenarios where you need to display or download generated content, or when working with media streams. The table below summarizes the primary use cases.
| Use Case | Description | Example |
|---|---|---|
| Image preview | Show uploaded image before submit | img.src = blobUrl |
| File download | Download generated content | a.href = blobUrl |
| Video playback | Stream recorded media | video.src = blobUrl |
| PDF preview | Display generated PDF | iframe.src = blobUrl |
| Audio playback | Play recorded audio | audio.src = blobUrl |
The image preview use case is particularly common—showing users their uploaded image before submitting a form. This provides instant feedback without any server communication.
One of the most useful patterns is generating downloadable files entirely in the browser.
File Download with Blob URL
These utility functions let you generate downloadable files from JavaScript data—useful for exporting user content, reports, or data exports. The browser handles the download with no server required.
// Download generated content as file
function downloadText(content, filename) {
const blob = new Blob([content], { type: 'text/plain' });
downloadBlob(blob, filename);
}
function downloadJSON(data, filename) {
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: 'application/json' });
downloadBlob(blob, filename);
}
function downloadCSV(rows, filename) {
const csv = rows.map(row => row.join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
downloadBlob(blob, filename);
}
function downloadBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Clean up
URL.revokeObjectURL(url);
}
// Usage
downloadText('Hello, World!', 'greeting.txt');
downloadJSON({ name: 'John', age: 30 }, 'data.json');
downloadCSV([['Name', 'Age'], ['John', 30]], 'people.csv');The pattern creates an invisible anchor element, sets its download attribute to specify the filename, clicks it programmatically, then cleans up. This works across modern browsers and handles the memory cleanup automatically.
Blob URLs are also essential for working with media streams—recording audio and video directly in the browser.
Media Streaming
The MediaRecorder API captures audio and video streams, producing Blob data that you can play back or download. Blob URLs make this seamless by providing a URL that media elements can use directly.
// Video recording and playback
async function recordVideo() {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const recorder = new MediaRecorder(stream);
const chunks = [];
recorder.ondataavailable = (e) => {
chunks.push(e.data);
};
recorder.onstop = () => {
const blob = new Blob(chunks, { type: 'video/webm' });
const videoUrl = URL.createObjectURL(blob);
const video = document.querySelector('video');
video.src = videoUrl;
video.play();
};
recorder.start();
// Stop after 5 seconds
setTimeout(() => recorder.stop(), 5000);
}
// Audio recording
async function recordAudio() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream);
const chunks = [];
recorder.ondataavailable = (e) => chunks.push(e.data);
recorder.onstop = () => {
const blob = new Blob(chunks, { type: 'audio/webm' });
const audioUrl = URL.createObjectURL(blob);
document.querySelector('audio').src = audioUrl;
};
recorder.start();
}The recorded chunks are collected in an array, then combined into a single Blob when recording stops. The blob URL can then be assigned to a video or audio element for playback, or passed to the download function to save the recording.
You might wonder when to use blob URLs versus data URLs. Let's compare them directly.
Blob URL vs Data URL
Both blob URLs and data URLs let you work with content without HTTP requests, but they have different characteristics. This table helps you choose the right approach for your use case.
| Aspect | Blob URL | Data URL |
|---|---|---|
| Size limit | Unlimited | URL length limits |
| Memory | Separate reference | Inline in document |
| Performance | Better for large files | Better for small files |
| Persistence | Session only | Can be stored |
| Shareability | Not shareable | Can be copied |
| Creation | createObjectURL() | Base64 encoding |
The key trade-off is persistence versus efficiency. Data URLs can be stored in localStorage or copied as text, but they duplicate the content. Blob URLs are memory-efficient but tied to the current page session.