Skip to content

Cloud Storage for Firebase: File Uploads, Downloads & Security

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Cloud Storage for Firebase: File Uploads, Downloads & Security. We cover key concepts, practical examples, and best practices to help you master this topic.

Cloud Storage for Firebase stores and serves user-generated content like images, videos, and documents using Google Cloud Storage buckets with Firebase SDK integration.

What You'll Learn

How to upload files from client apps, manage file metadata and organization, generate download URLs, handle upload progress, and secure files with Storage Security Rules.

Why It Matters

File storage requires scaling, CDN delivery, and access control. Cloud Storage provides global CDN, automatic scaling, and Firebase Security Rules integration. Durga Antivirus Pro stores threat report PDFs and device screenshots in Cloud Storage with user-scoped access.

Real-World Use

A security app where users upload suspicious file samples for analysis. Each sample is stored in a user-specific path, analyzed by Cloud Functions, and results are shared via signed URLs.

flowchart LR
    A["Client App\nUpload File"] --> B["Cloud Storage\nBucket"]
    B --> C["Security Rules\nCheck Auth"]
    C --> D["File Stored\n+ Metadata"]
    D --> E["Download URL\nGenerated"]
    D --> F["Cloud Functions\nProcess File"]
    style B fill:#dbeafe,stroke:#2563eb
    style C fill:#fef3c7,stroke:#d97706

Uploading Files

import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";

async function uploadFile(file) {
  const userId = auth.currentUser.uid;
  const storageRef = ref(storage, `users/${userId}/samples/${file.name}`);

  // Upload with progress tracking
  const uploadTask = uploadBytesResumable(storageRef, file);

  uploadTask.on("state_changed",
    (snapshot) => {
      const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
      console.log("Upload progress:", progress.toFixed(1) + "%");
    },
    (error) => {
      console.error("Upload failed:", error.message);
    },
    async () => {
      const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
      console.log("File available at:", downloadURL);
    }
  );
}

uploadFile(new File(["suspicious.exe"], "sample_malware.exe"));
// Expected output: Upload progress: 45.2%
//                  Upload progress: 100.0%
//                  File available at: https://firebasestorage.googleapis.com/...

File Metadata

import { ref, updateMetadata, getMetadata } from "firebase/storage";

async function manageMetadata(filePath) {
  const fileRef = ref(storage, filePath);

  // Set custom metadata
  await updateMetadata(fileRef, {
    customMetadata: {
      userId: auth.currentUser.uid,
      threatLevel: "high",
      scanStatus: "pending"
    },
    contentType: "application/octet-stream",
    cacheControl: "public,max-age=3600"
  });
  console.log("Metadata updated");

  // Read metadata
  const metadata = await getMetadata(fileRef);
  console.log("File size:", metadata.size, "bytes");
  console.log("Content type:", metadata.contentType);
  console.log("Custom metadata:", metadata.customMetadata);
}
// Expected output: Metadata updated
//                  File size: 1048576 bytes
//                  Content type: application/octet-stream
//                  Custom metadata: { userId: "abc", threatLevel: "high", ... }

Download URLs and Signed URLs

import { ref, getDownloadURL, listAll } from "firebase/storage";

async function listAndDownload(prefix) {
  const listRef = ref(storage, prefix);
  const result = await listAll(listRef);

  for (const itemRef of result.items) {
    const url = await getDownloadURL(itemRef);
    console.log(itemRef.name, ":", url);
  }
}

listAndDownload("users/abc123/samples/");
// Expected output: sample_malware.exe : https://firebasestorage.googleapis.com/...
//                  report_2026.pdf : https://firebasestorage.googleapis.com/...

Deleting Files

import { ref, deleteObject } from "firebase/storage";

async function deleteFile(filePath) {
  const fileRef = ref(storage, filePath);
  try {
    await deleteObject(fileRef);
    console.log("File deleted:", filePath);
  } catch (error) {
    console.error("Delete failed:", error.message);
  }
}

deleteFile("users/abc123/samples/temp_upload.exe");
// Expected output: File deleted: users/abc123/samples/temp_upload.exe

Common Mistakes

1. Storing Files in the Root Bucket

Without path prefixes, all files live in a flat namespace. Organize files by user ID or category to make Security Rules easier and list operations faster.

2. Hardcoding Bucket Name

Buckets are globally unique and can change between environments. Use the default bucket from getStorage() or configure it per environment.

3. Not Handling Upload Interruptions

Uploads can fail due to network issues. Use uploadBytesResumable (not uploadBytes) to resume interrupted uploads.

4. Exposing Download URLs Without Auth

Download URLs are publicly accessible by default. Use Firebase Security Rules or signed URLs with expiration for private content.

5. Forgetting to Clean Up Orphaned Files

When a user deletes their account, their files remain in Storage. Implement cleanup logic with Cloud Functions triggered on user deletion.

Practice Questions

  1. What is the difference between uploadBytes and uploadBytesResumable?
  2. How do you control access to files in Cloud Storage?
  3. What is the purpose of file metadata?
  4. How do you generate a publicly shareable link for a file?

Answers:

  1. uploadBytesResumable supports progress tracking, pause/resume, and retry. uploadBytes is a simple one-shot upload.
  2. Use Storage Security Rules with conditions on request.auth and path matching to control read/write access.
  3. Metadata stores content type, cache control, and custom key-value pairs for describing the file's properties.
  4. Call getDownloadURL() to get a long-lived download URL, or use getSignedUrl() from the Admin SDK for time-limited signed URLs.

Challenge: Build a file submission system for Durga Antivirus Pro: users upload suspicious files, stored per-user with metadata (threat level, scan status), with progress bars and resumable uploads.

FAQ

What file size limits does Cloud Storage have?

Files can be up to 5 TB. Uploads via the Firebase SDK have a practical limit based on client memory and network stability.

How does Cloud Storage pricing work?

You pay for data stored (GB/month), data transferred (egress), and operations (upload, download, delete). The free tier includes 5 GB storage and 1 GB/day egress.

Can I use an existing GCS bucket with Firebase?

Yes. In the Firebase Console, you can link an existing Google Cloud Storage bucket. Security Rules and SDK work the same way.

Is Cloud Storage PCI-DSS compliant?

Google Cloud Storage is SOC 1/2/3, ISO 27001, and HIPAA compliant. PCI DSS compliance requires additional configuration and a Business Associate Agreement.

How do I serve files through a custom domain?

Configure a CNAME record pointing to c.storage.googleapis.com and use Firebase Hosting rewrites to serve from the bucket.

Mini Project

Build a file management system: upload files with progress tracking, organize by user ID, set custom metadata, implement Security Rules for user-only access, and provide download links for authenticated users.

What's Next

Storage Security Rules — secure your Cloud Storage files with granular access control.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro