Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Validate File Size in Firebase Storage

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.

What you'll learn

  • How to check file size on the client before uploading to Firebase Storage
  • How to write Storage security rules that enforce file size limits
  • How to combine size validation with content type checks for robust upload protection
  • How to display user-friendly error messages when files exceed the limit
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read8-12 minFirebase JS SDK v9+, Firebase Storage, all Firebase plansMarch 2026RapidDev Engineering Team
TL;DR

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

1

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.

typescript
1const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5 MB in bytes
2
3function 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 // valid
9}
10
11// Usage with a file input
12const input = document.querySelector('input[type="file"]') as HTMLInputElement
13input.addEventListener('change', () => {
14 const file = input.files?.[0]
15 if (!file) return
16
17 const error = validateFile(file)
18 if (error) {
19 alert(error)
20 input.value = '' // clear the invalid selection
21 return
22 }
23
24 // Proceed with upload
25 uploadFile(file)
26})

Expected result: Files larger than 5 MB are rejected immediately with a user-friendly error message before any upload begins.

2

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.

typescript
1// storage.rules
2rules_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 != null
8 && request.auth.uid == userId
9 && 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.

3

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.

typescript
1// storage.rules
2rules_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 != null
8 && request.auth.uid == userId
9 && request.resource.size < 5 * 1024 * 1024
10 && request.resource.contentType.matches('image/.*');
11 }
12
13 match /documents/{userId}/{docId} {
14 allow read: if request.auth != null;
15 allow write: if request.auth != null
16 && request.auth.uid == userId
17 && request.resource.size < 10 * 1024 * 1024
18 && 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.

4

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.

typescript
1import { getStorage, ref, uploadBytes } from 'firebase/storage'
2
3const storage = getStorage()
4
5async function uploadFile(file: File) {
6 // Client-side check first
7 if (file.size > 5 * 1024 * 1024) {
8 throw new Error('File exceeds 5 MB limit')
9 }
10
11 const storageRef = ref(storage, `uploads/${userId}/${file.name}`)
12
13 try {
14 const snapshot = await uploadBytes(storageRef, file, {
15 contentType: file.type
16 })
17 console.log('Upload complete:', snapshot.metadata.fullPath)
18 return snapshot
19 } 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 error
24 }
25}

Expected result: Uploads that pass client-side validation but fail security rules are caught and surfaced to the user.

5

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.

typescript
1import { getStorage, ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage'
2
3const storage = getStorage()
4
5function 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.type
9 })
10
11 return new Promise<string>((resolve, reject) => {
12 uploadTask.on('state_changed',
13 (snapshot) => {
14 const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
15 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

src/lib/storage-upload.ts
1// src/lib/storage-upload.ts
2import {
3 getStorage,
4 ref,
5 uploadBytesResumable,
6 getDownloadURL
7} from 'firebase/storage'
8
9const storage = getStorage()
10
11const SIZE_LIMITS: Record<string, number> = {
12 image: 5 * 1024 * 1024, // 5 MB
13 document: 10 * 1024 * 1024, // 10 MB
14 video: 100 * 1024 * 1024 // 100 MB
15}
16
17function getFileCategory(file: File): string {
18 if (file.type.startsWith('image/')) return 'image'
19 if (file.type.startsWith('video/')) return 'video'
20 return 'document'
21}
22
23export 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 null
32}
33
34export function uploadFile(
35 file: File,
36 userId: string,
37 onProgress?: (percent: number) => void
38): Promise<string> {
39 const sizeError = validateFileSize(file)
40 if (sizeError) return Promise.reject(new Error(sizeError))
41
42 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.type
47 })
48
49 return new Promise((resolve, reject) => {
50 uploadTask.on('state_changed',
51 (snapshot) => {
52 const percent = Math.round(
53 (snapshot.bytesTransferred / snapshot.totalBytes) * 100
54 )
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.

ChatGPT Prompt

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.

Firebase Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.