Firebase Storage uses virtual folders created by forward slashes in file paths — there are no actual folder objects. Upload files to paths like users/{uid}/avatars/photo.jpg to create a logical hierarchy. Use listAll() and list() to browse folder contents, and write security rules that match path segments to control access per folder. This pattern keeps files organized and security rules manageable as your app grows.
Structuring Files With Virtual Folders in Firebase Storage
Firebase Storage is a flat object store — it has no real directory hierarchy. Folders are created implicitly by including forward slashes in file paths. The path users/abc123/avatar.jpg creates the appearance of a users folder containing an abc123 folder. This tutorial covers how to design a folder structure, upload files to specific paths, list folder contents, and write security rules that restrict access based on folder paths.
Prerequisites
- A Firebase project with Storage enabled in the Firebase Console
- Firebase JS SDK installed and initialized in your web app
- A Storage bucket created (default bucket is included with every project)
- Basic understanding of Firebase Authentication for user-scoped paths
Step-by-step guide
Design a folder structure for your app
Design a folder structure for your app
Plan your folder structure before uploading files. A common pattern uses the authenticated user's UID as a top-level folder, with subfolders for different file types. For shared content, use a public or shared folder at the root level. Keep paths short and consistent — they become part of your security rules and download URLs.
1// Recommended folder structures:23// User-scoped files4// users/{uid}/avatar/profile.jpg5// users/{uid}/documents/resume.pdf6// users/{uid}/uploads/photo-001.jpg78// Shared/public content9// public/banners/hero.jpg10// public/icons/logo.svg1112// Team/org-scoped files13// teams/{teamId}/assets/logo.png14// teams/{teamId}/documents/contract.pdf1516// Timestamped uploads for uniqueness17// users/{uid}/photos/{timestamp}-{filename}Expected result: You have a documented folder structure that maps to your app's data model and supports your security requirements.
Upload files to specific folder paths
Upload files to specific folder paths
Use the ref() function with a full path string to place files in the correct folder. The folder is created automatically when the first file is uploaded to that path. You do not need to create folders in advance. Set custom metadata on uploads to track file type, uploader, or other attributes that help with organization.
1import { getStorage, ref, uploadBytes, uploadBytesResumable } from "firebase/storage";2import { getAuth } from "firebase/auth";34const storage = getStorage();5const auth = getAuth();67async function uploadUserFile(8 file: File,9 subfolder: string10): Promise<string> {11 const user = auth.currentUser;12 if (!user) throw new Error("Must be logged in to upload");1314 // Build the path: users/{uid}/{subfolder}/{filename}15 const timestamp = Date.now();16 const safeName = file.name.replace(/[^a-zA-Z0-9.-]/g, "_");17 const filePath = `users/${user.uid}/${subfolder}/${timestamp}-${safeName}`;1819 const storageRef = ref(storage, filePath);20 const metadata = {21 customMetadata: {22 uploadedBy: user.uid,23 originalName: file.name,24 },25 };2627 await uploadBytes(storageRef, file, metadata);28 return filePath;29}3031// Usage32// uploadUserFile(selectedFile, "documents");Expected result: Files are uploaded to structured paths like users/abc123/documents/1711612800000-report.pdf with custom metadata.
List files in a folder using listAll() and list()
List files in a folder using listAll() and list()
Use listAll() to get every item and subfolder in a path, or use list() with maxResults for paginated results. The listAll() function returns a ListResult with items (files) and prefixes (subfolders). For folders with many files, use list() with pagination to avoid loading everything at once. Both functions only list direct children — they do not recurse into subfolders.
1import { getStorage, ref, listAll, list, getDownloadURL } from "firebase/storage";23const storage = getStorage();45// List all files in a folder6async function listFolder(folderPath: string) {7 const folderRef = ref(storage, folderPath);8 const result = await listAll(folderRef);910 // Files in this folder11 for (const item of result.items) {12 const url = await getDownloadURL(item);13 console.log(`File: ${item.name}, URL: ${url}`);14 }1516 // Subfolders17 for (const prefix of result.prefixes) {18 console.log(`Subfolder: ${prefix.name}`);19 }20}2122// Paginated listing for large folders23async function listFolderPaginated(24 folderPath: string,25 pageSize: number = 2026) {27 const folderRef = ref(storage, folderPath);28 let pageToken: string | undefined;29 const allItems = [];3031 do {32 const result = await list(folderRef, {33 maxResults: pageSize,34 pageToken,35 });36 allItems.push(...result.items);37 pageToken = result.nextPageToken;38 } while (pageToken);3940 return allItems;41}Expected result: You can browse folder contents, display file lists in your UI, and navigate subfolders programmatically.
Write security rules scoped to folder paths
Write security rules scoped to folder paths
Firebase Storage security rules use path matching with wildcards. Match path segments to restrict access to specific folders. The most common pattern uses {userId} as a wildcard that must match request.auth.uid, ensuring users can only access their own folder. Always validate content type and file size in rules to prevent abuse.
1// storage.rules2rules_version = '2';3service firebase.storage {4 match /b/{bucket}/o {56 // User-scoped files: only the owner can read/write7 match /users/{userId}/{allPaths=**} {8 allow read, write: if request.auth != null9 && request.auth.uid == userId;10 }1112 // User avatars: anyone can read, only owner can write13 match /users/{userId}/avatar/{fileName} {14 allow read: if true;15 allow write: if request.auth != null16 && request.auth.uid == userId17 && request.resource.size < 5 * 1024 * 102418 && request.resource.contentType.matches('image/.*');19 }2021 // Public folder: anyone can read, no one can write via client22 match /public/{allPaths=**} {23 allow read: if true;24 allow write: if false;25 }2627 // Team files: only team members can access28 match /teams/{teamId}/{allPaths=**} {29 allow read, write: if request.auth != null30 && request.auth.token.teamId == teamId;31 }32 }33}Expected result: Security rules enforce folder-level access control — users can only read and write files in their own folders.
Delete all files in a folder
Delete all files in a folder
Firebase Storage has no built-in delete folder operation. To delete a folder and all its contents, list all files in the folder and delete each one individually. For large folders, use the paginated list() approach and delete in batches. This is a common operation when users delete their account or when cleaning up temporary uploads.
1import { getStorage, ref, listAll, deleteObject } from "firebase/storage";23const storage = getStorage();45async function deleteFolder(folderPath: string): Promise<number> {6 const folderRef = ref(storage, folderPath);7 const result = await listAll(folderRef);8 let deletedCount = 0;910 // Delete all files in this folder11 const deletePromises = result.items.map(async (itemRef) => {12 await deleteObject(itemRef);13 deletedCount++;14 });1516 // Recursively delete subfolders17 const subfolderPromises = result.prefixes.map((prefix) =>18 deleteFolder(prefix.fullPath)19 );2021 await Promise.all([...deletePromises, ...subfolderPromises]);2223 for (const subfolder of subfolderPromises) {24 deletedCount += await subfolder;25 }2627 return deletedCount;28}2930// Usage: deleteFolder(`users/${userId}`);Expected result: All files within the specified folder path are deleted, including files in nested subfolders.
Complete working example
1// Firebase Storage — Folder Organization Utilities2import { initializeApp } from "firebase/app";3import {4 getStorage,5 ref,6 uploadBytes,7 listAll,8 list,9 getDownloadURL,10 deleteObject,11 getMetadata,12} from "firebase/storage";13import { getAuth } from "firebase/auth";1415const app = initializeApp({ /* your config */ });16const storage = getStorage(app);17const auth = getAuth(app);1819// Upload a file to a user-scoped folder20export async function uploadToFolder(21 file: File,22 folder: string23): Promise<{ path: string; url: string }> {24 const user = auth.currentUser;25 if (!user) throw new Error("Authentication required");2627 const safeName = file.name.replace(/[^a-zA-Z0-9.-]/g, "_");28 const path = `users/${user.uid}/${folder}/${Date.now()}-${safeName}`;29 const fileRef = ref(storage, path);3031 await uploadBytes(fileRef, file, {32 customMetadata: { uploadedBy: user.uid },33 });3435 const url = await getDownloadURL(fileRef);36 return { path, url };37}3839// List all files in a folder with metadata40export async function listFolderContents(folderPath: string) {41 const folderRef = ref(storage, folderPath);42 const result = await listAll(folderRef);4344 const files = await Promise.all(45 result.items.map(async (itemRef) => {46 const [url, metadata] = await Promise.all([47 getDownloadURL(itemRef),48 getMetadata(itemRef),49 ]);50 return {51 name: itemRef.name,52 fullPath: itemRef.fullPath,53 url,54 size: metadata.size,55 contentType: metadata.contentType,56 updated: metadata.updated,57 };58 })59 );6061 const subfolders = result.prefixes.map((p) => ({62 name: p.name,63 fullPath: p.fullPath,64 }));6566 return { files, subfolders };67}6869// Paginated listing for large folders70export async function listFolderPage(71 folderPath: string,72 pageSize: number = 20,73 pageToken?: string74) {75 const folderRef = ref(storage, folderPath);76 const result = await list(folderRef, { maxResults: pageSize, pageToken });77 return {78 items: result.items.map((i) => ({ name: i.name, path: i.fullPath })),79 nextPageToken: result.nextPageToken,80 };81}8283// Recursively delete a folder and all contents84export async function deleteFolder(folderPath: string): Promise<number> {85 const folderRef = ref(storage, folderPath);86 const result = await listAll(folderRef);87 let count = 0;8889 await Promise.all(90 result.items.map(async (item) => {91 await deleteObject(item);92 count++;93 })94 );9596 for (const prefix of result.prefixes) {97 count += await deleteFolder(prefix.fullPath);98 }99100 return count;101}Common mistakes when organizing Folders and File Paths in Firebase Storage
Why it's a problem: Trying to create an empty folder in Firebase Storage — folders only exist when they contain at least one file
How to avoid: Folders in Firebase Storage are virtual and created implicitly by file paths. You cannot create an empty folder. Upload a file to a path and the folder appears automatically.
Why it's a problem: Using listAll() on folders with thousands of files, causing memory issues and slow performance
How to avoid: Use list() with the maxResults option for paginated listing. Process files in pages of 20-100 items to keep memory usage manageable.
Why it's a problem: Not including the user's UID in the storage path, making it impossible to write ownership-based security rules
How to avoid: Always include request.auth.uid as a path segment (e.g., users/{uid}/...) so security rules can verify that the authenticated user owns the folder.
Why it's a problem: Forgetting to deploy updated security rules after changing the folder structure
How to avoid: Run firebase deploy --only storage after modifying storage.rules. Rules changes do not take effect until deployed.
Best practices
- Include the user's UID as a top-level folder segment to enable ownership-based security rules
- Use timestamps or UUIDs in filenames to prevent accidental overwrites of same-named files
- Sanitize filenames by removing special characters before using them in storage paths
- Use list() with pagination for folders that may contain more than 100 files
- Write security rules that validate content type and file size in addition to authentication
- Use a consistent naming convention for folders (lowercase, hyphens) across your app
- Create a public folder with read-only rules for assets that should be accessible without authentication
- Use Cloud Functions with the Admin SDK for bulk operations like folder deletion on large datasets
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to organize files in Firebase Storage for a project management app. Each project has a team that uploads documents and images. Design a folder structure that supports user-scoped uploads, team-shared files, and public assets. Write TypeScript utility functions for uploading to a specific folder, listing folder contents with metadata, and deleting an entire folder recursively. Include Firebase Storage security rules.
Create a Firebase Storage folder structure for my app with user-scoped paths (users/{uid}/avatars, users/{uid}/documents) and a public folder for shared assets. Write security rules so users can only access their own folders, avatars are publicly readable, and uploads are limited to 5 MB images. Include a TypeScript function that uploads a file to the correct folder path.
Frequently asked questions
Do folders actually exist in Firebase Storage?
No. Firebase Storage is a flat object store. Folders are virtual — they are created implicitly by the forward slashes in file paths. A file at users/abc/photo.jpg creates the appearance of a users folder and an abc subfolder, but no folder objects exist.
Can I rename or move a folder in Firebase Storage?
There is no rename or move operation. To move files, you must download each file and re-upload it to the new path, then delete the original. For large moves, use a Cloud Function with the Admin SDK.
What happens to a folder when I delete all files in it?
The folder disappears. Since folders are virtual and defined by file paths, a folder with no files simply does not exist. listAll() will not return it as a prefix.
How do I list only subfolders without listing files?
The listAll() and list() functions return both items (files) and prefixes (subfolders). To get only subfolders, use result.prefixes and ignore result.items.
Is there a limit to how many files I can have in one folder?
There is no limit on files per folder. However, listAll() loads all references into memory, so for folders with thousands of files, use the paginated list() function with maxResults to avoid performance issues.
Can I set different security rules for different folders?
Yes. Storage security rules use path matching with wildcards. You can write different rules for each folder path, such as allowing public read on /public/** while restricting /users/{userId}/** to the authenticated owner.
Can RapidDev help design my Firebase Storage folder structure?
Yes. RapidDev can design a storage architecture that matches your app's data model, write security rules for each folder path, and build utility functions for uploads, listings, and cleanup.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation