Validate file size in Firebase Storage at two layers: client-side by checking the File object's size property before calling uploadBytes, and server-side through Storage security rules using request.resource.size. The security rule is the critical layer because client-side checks can be bypassed. A rule like request.resource.size < 5 * 1024 * 1024 enforces a 5 MB limit regardless of how the upload is initiated.
Enforcing File Size Limits in Firebase Storage
Accepting arbitrarily large file uploads can exhaust your storage budget and degrade user experience. This tutorial shows you how to validate file size both on the client side (for instant user feedback) and in Firebase Storage security rules (for enforcement that cannot be circumvented). You will also learn how to combine size limits with content type validation for a complete upload protection strategy.
Prerequisites
- A Firebase project with Cloud Storage enabled
- Firebase JS SDK v9+ installed in your project
- Basic understanding of Firebase Storage security rules
- An HTML file input or file picker in your app
Step-by-step guide
Add client-side file size validation
Add client-side file size validation
Before uploading, check the File object's size property (in bytes) against your maximum allowed size. This provides instant feedback to the user without consuming bandwidth or triggering a server-side rejection. Show a clear error message if the file is too large.
1const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5 MB in bytes23function validateFile(file: File): string | null {4 if (file.size > MAX_FILE_SIZE) {5 const sizeMB = (file.size / (1024 * 1024)).toFixed(1)6 return `File is ${sizeMB} MB. Maximum allowed size is 5 MB.`7 }8 return null // valid9}1011// Usage with a file input12const input = document.querySelector('input[type="file"]') as HTMLInputElement13input.addEventListener('change', () => {14 const file = input.files?.[0]15 if (!file) return1617 const error = validateFile(file)18 if (error) {19 alert(error)20 input.value = '' // clear the invalid selection21 return22 }2324 // Proceed with upload25 uploadFile(file)26})Expected result: Files larger than 5 MB are rejected immediately with a user-friendly error message before any upload begins.
Write Storage security rules to enforce size limits
Write Storage security rules to enforce size limits
Client-side validation can be bypassed by a malicious user. Storage security rules are enforced server-side and cannot be circumvented. Use request.resource.size to check the incoming file size. This rule rejects the upload at the Firebase level if the file exceeds the limit.
1// storage.rules2rules_version = '2';3service firebase.storage {4 match /b/{bucket}/o {5 match /uploads/{userId}/{allPaths=**} {6 allow read: if request.auth != null;7 allow write: if request.auth != null8 && request.auth.uid == userId9 && request.resource.size < 5 * 1024 * 1024;10 }11 }12}Expected result: Any upload larger than 5 MB is rejected by Firebase Storage with a permission denied error, regardless of how the upload was initiated.
Combine size validation with content type checks
Combine size validation with content type checks
In addition to size limits, validate the content type to prevent users from uploading unexpected file types. Storage security rules can check request.resource.contentType. Combine both checks in a single rule for comprehensive upload protection.
1// storage.rules2rules_version = '2';3service firebase.storage {4 match /b/{bucket}/o {5 match /images/{userId}/{imageId} {6 allow read: if request.auth != null;7 allow write: if request.auth != null8 && request.auth.uid == userId9 && request.resource.size < 5 * 1024 * 102410 && request.resource.contentType.matches('image/.*');11 }1213 match /documents/{userId}/{docId} {14 allow read: if request.auth != null;15 allow write: if request.auth != null16 && request.auth.uid == userId17 && request.resource.size < 10 * 1024 * 102418 && request.resource.contentType in [19 'application/pdf',20 'application/msword',21 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'22 ];23 }24 }25}Expected result: Images are limited to 5 MB and must be image/* content types. Documents are limited to 10 MB and must be PDF or Word files.
Upload with error handling for rule rejections
Upload with error handling for rule rejections
When a security rule rejects an upload, the Firebase SDK throws an error with the code 'storage/unauthorized'. Catch this error and display a helpful message. The user will see the client-side validation first, but the security rule serves as the backstop.
1import { getStorage, ref, uploadBytes } from 'firebase/storage'23const storage = getStorage()45async function uploadFile(file: File) {6 // Client-side check first7 if (file.size > 5 * 1024 * 1024) {8 throw new Error('File exceeds 5 MB limit')9 }1011 const storageRef = ref(storage, `uploads/${userId}/${file.name}`)1213 try {14 const snapshot = await uploadBytes(storageRef, file, {15 contentType: file.type16 })17 console.log('Upload complete:', snapshot.metadata.fullPath)18 return snapshot19 } catch (error: any) {20 if (error.code === 'storage/unauthorized') {21 throw new Error('Upload rejected: file may exceed size limit or you lack permission')22 }23 throw error24 }25}Expected result: Uploads that pass client-side validation but fail security rules are caught and surfaced to the user.
Add a progress indicator for valid uploads
Add a progress indicator for valid uploads
For files within the size limit, use uploadBytesResumable to show upload progress. This improves user experience for larger files that take several seconds. The progress callback fires as bytes are transferred.
1import { getStorage, ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage'23const storage = getStorage()45function uploadWithProgress(file: File, onProgress: (percent: number) => void) {6 const storageRef = ref(storage, `uploads/${userId}/${file.name}`)7 const uploadTask = uploadBytesResumable(storageRef, file, {8 contentType: file.type9 })1011 return new Promise<string>((resolve, reject) => {12 uploadTask.on('state_changed',13 (snapshot) => {14 const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 10015 onProgress(Math.round(percent))16 },17 (error) => reject(error),18 async () => {19 const url = await getDownloadURL(uploadTask.snapshot.ref)20 resolve(url)21 }22 )23 })24}Expected result: The progress callback fires with percentage updates during upload, and the function resolves with the download URL on completion.
Complete working example
1// src/lib/storage-upload.ts2import {3 getStorage,4 ref,5 uploadBytesResumable,6 getDownloadURL7} from 'firebase/storage'89const storage = getStorage()1011const SIZE_LIMITS: Record<string, number> = {12 image: 5 * 1024 * 1024, // 5 MB13 document: 10 * 1024 * 1024, // 10 MB14 video: 100 * 1024 * 1024 // 100 MB15}1617function getFileCategory(file: File): string {18 if (file.type.startsWith('image/')) return 'image'19 if (file.type.startsWith('video/')) return 'video'20 return 'document'21}2223export function validateFileSize(file: File): string | null {24 const category = getFileCategory(file)25 const maxSize = SIZE_LIMITS[category]26 if (file.size > maxSize) {27 const maxMB = (maxSize / (1024 * 1024)).toFixed(0)28 const fileMB = (file.size / (1024 * 1024)).toFixed(1)29 return `File is ${fileMB} MB. Maximum for ${category}s is ${maxMB} MB.`30 }31 return null32}3334export function uploadFile(35 file: File,36 userId: string,37 onProgress?: (percent: number) => void38): Promise<string> {39 const sizeError = validateFileSize(file)40 if (sizeError) return Promise.reject(new Error(sizeError))4142 const category = getFileCategory(file)43 const path = `${category}s/${userId}/${Date.now()}-${file.name}`44 const storageRef = ref(storage, path)45 const uploadTask = uploadBytesResumable(storageRef, file, {46 contentType: file.type47 })4849 return new Promise((resolve, reject) => {50 uploadTask.on('state_changed',51 (snapshot) => {52 const percent = Math.round(53 (snapshot.bytesTransferred / snapshot.totalBytes) * 10054 )55 onProgress?.(percent)56 },57 (error) => {58 if (error.code === 'storage/unauthorized') {59 reject(new Error('Upload rejected by security rules'))60 } else {61 reject(error)62 }63 },64 async () => {65 const url = await getDownloadURL(uploadTask.snapshot.ref)66 resolve(url)67 }68 )69 })70}Common mistakes when validating File Size in Firebase Storage
Why it's a problem: Relying only on client-side validation without Storage security rules, allowing users to bypass size limits
How to avoid: Always enforce file size limits in Storage security rules using request.resource.size. Client-side checks improve UX but are not a security mechanism.
Why it's a problem: Using megabytes in security rules instead of bytes — writing request.resource.size < 5 expecting 5 MB but actually enforcing 5 bytes
How to avoid: Storage rule sizes are in bytes. Use 5 * 1024 * 1024 for 5 MB. Firestore rules support arithmetic expressions.
Why it's a problem: Not setting contentType in upload metadata, causing the contentType security rule check to fail
How to avoid: Always pass { contentType: file.type } in the upload metadata. Without it, Firebase may assign a default content type that does not match your rule.
Best practices
- Validate file size on the client for instant user feedback, and in security rules for enforcement
- Use different size limits for different file types (images, documents, videos) by organizing uploads into separate storage paths
- Always set contentType in the upload metadata to ensure security rules can validate the file type
- Use uploadBytesResumable instead of uploadBytes for larger files so you can show progress and handle pauses
- Generate unique filenames using timestamps or UUIDs to prevent accidental overwrites
- For apps handling large volumes of user uploads with different validation requirements, RapidDev can help build a robust file processing pipeline with resizing and virus scanning
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Show me how to validate file size before uploading to Firebase Storage. I need client-side validation that checks the file size and shows an error, plus Firebase Storage security rules that enforce a 5 MB limit for images and 10 MB limit for PDFs. Include the upload function with error handling.
Add file size validation to my Firebase Storage upload flow. I need a utility function that validates file size by type (5 MB for images, 10 MB for documents), Storage security rules with size and contentType enforcement, and an upload function using uploadBytesResumable with progress tracking. Use Firebase modular SDK v9+ TypeScript.
Frequently asked questions
What is the maximum file size Firebase Storage supports?
Firebase Storage supports files up to 5 TB. However, the practical limit for browser uploads is lower due to browser memory constraints and network timeouts. For files over 100 MB, use uploadBytesResumable which supports resumable uploads.
Can I enforce different size limits for different file types in security rules?
Yes. Use separate match paths for different upload destinations and apply different size limits to each. For example, match /images/{path} with a 5 MB limit and match /videos/{path} with a 100 MB limit.
Does the Spark (free) plan have different file size limits?
The Spark plan blocks executable file uploads (.exe, .dll, .apk) but does not impose a different maximum file size compared to Blaze. The 5 GB total storage limit on Spark is the main constraint.
How do I check file size in a React component?
Access event.target.files[0].size in the onChange handler of your file input. The size is in bytes. Compare it to your maximum before calling the upload function.
What error does Firebase throw when a file exceeds the security rule size limit?
Firebase throws an error with code 'storage/unauthorized' and message 'User does not have permission to access'. The error does not specifically mention the size limit — it is a generic permission denied. Your client-side validation should provide the specific size error message.
Can I validate file dimensions (width and height) in security rules?
No. Storage security rules cannot inspect image dimensions. You can check dimensions client-side using the Image API (create an Image element and check naturalWidth/naturalHeight), or validate server-side using a Cloud Function triggered by Storage uploads.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation