Firebase Storage Upload Download
Uploading and downloading files in Firebase Storage requires two things: a storage reference pointing to the file's path, and the file data itself. Firebase provides progress tracking during uploads and secure download URLs for sharing files after upload.
Uploading a File from a Browser Input
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import { storage } from "./firebase";
async function uploadFile(file, userId) {
// Build the file path using the user's ID
const filePath = "profile-photos/" + userId + "/" + file.name;
const storageRef = ref(storage, filePath);
// Start the upload
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on(
"state_changed",
(snapshot) => {
// Track progress
const percent = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
console.log("Upload progress:", percent + "%");
},
(error) => {
// Handle errors
console.error("Upload failed:", error.message);
reject(error);
},
async () => {
// Upload complete — get the download URL
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
console.log("File available at:", downloadURL);
resolve(downloadURL);
}
);
});
}
Connecting the Upload to an HTML Input
<input type="file" id="file-input" accept="image/*" /> <button id="upload-btn">Upload Photo</button> <p id="upload-status"></p> <progress id="upload-bar" value="0" max="100"></progress>
document.getElementById("upload-btn").addEventListener("click", async () => {
const fileInput = document.getElementById("file-input");
const file = fileInput.files[0];
if (!file) {
alert("Please select a file first.");
return;
}
const userId = auth.currentUser.uid;
const filePath = "profile-photos/" + userId + "/" + file.name;
const storageRef = ref(storage, filePath);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on("state_changed",
(snapshot) => {
const percent = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
document.getElementById("upload-bar").value = percent;
document.getElementById("upload-status").textContent = percent + "% uploaded";
},
(error) => {
document.getElementById("upload-status").textContent = "Error: " + error.message;
},
async () => {
const url = await getDownloadURL(uploadTask.snapshot.ref);
document.getElementById("upload-status").textContent = "Upload complete!";
console.log("Download URL:", url);
}
);
});
Simple Upload Without Progress Tracking
For small files where progress tracking is unnecessary, use uploadBytes:
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
async function uploadSmallFile(file) {
const storageRef = ref(storage, "documents/" + file.name);
const snapshot = await uploadBytes(storageRef, file);
const url = await getDownloadURL(snapshot.ref);
return url;
}
Getting the Download URL
The download URL is a public HTTPS link that anyone with the link can use to access the file — as long as your security rules permit it. Store this URL in Firestore alongside the document that references the file:
import { doc, updateDoc } from "firebase/firestore";
import { db } from "./firebase";
// After upload completes, save URL to Firestore
const downloadURL = await getDownloadURL(snapshot.ref);
await updateDoc(doc(db, "users", userId), {
photoURL: downloadURL
});
Getting a Download URL for an Existing File
import { ref, getDownloadURL } from "firebase/storage";
const fileRef = ref(storage, "profile-photos/uid_alice/photo.jpg");
const url = await getDownloadURL(fileRef);
// Display in an img tag
document.getElementById("profile-img").src = url;
Uploading from a Data URL or Base64 String
import { ref, uploadString } from "firebase/storage";
// Upload a base64-encoded image
const base64Image = "data:image/png;base64,iVBOR...";
const storageRef = ref(storage, "thumbnails/thumb_001.png");
await uploadString(storageRef, base64Image, "data_url");
const url = await getDownloadURL(storageRef);
console.log("Thumbnail URL:", url);
Deleting a File
import { ref, deleteObject } from "firebase/storage";
const fileRef = ref(storage, "profile-photos/uid_alice/old-photo.jpg");
await deleteObject(fileRef);
console.log("File deleted.");
Upload State Types
During an upload, the state_changed listener reports upload states:
running— upload is actively transferring datapaused— upload was paused by callinguploadTask.pause()canceled— upload was stopped by callinguploadTask.cancel()
You can pause and resume uploads, which is useful for large files on unstable connections:
// Pause uploadTask.pause(); // Resume uploadTask.resume(); // Cancel uploadTask.cancel();
Key Takeaway
Use uploadBytesResumable for large files where progress tracking matters and uploadBytes for small files. Always call getDownloadURL after upload and store the returned URL in Firestore for later use. Use deleteObject to remove files when users delete their accounts or content. Pair file paths with the user's UID to enforce per-user access in security rules.
