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

How to Prevent File Overwrite in Firebase Storage

Firebase Storage overwrites files silently when you upload to an existing path. To prevent overwrites, generate unique filenames by appending a UUID or timestamp before uploading. You can also use Storage security rules to block writes when a file already exists at the target path by checking resource == null. For additional safety, check if the file exists client-side with getDownloadURL before uploading, though this has a race condition that only security rules can close.

What you'll learn

  • How Firebase Storage handles uploads to existing file paths
  • How to generate unique filenames with UUID or timestamp
  • How to write security rules that block file overwrites
  • How to check if a file exists before uploading
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read10-15 minFirebase JS SDK v9+, all plansMarch 2026RapidDev Engineering Team
TL;DR

Firebase Storage overwrites files silently when you upload to an existing path. To prevent overwrites, generate unique filenames by appending a UUID or timestamp before uploading. You can also use Storage security rules to block writes when a file already exists at the target path by checking resource == null. For additional safety, check if the file exists client-side with getDownloadURL before uploading, though this has a race condition that only security rules can close.

Preventing File Overwrites in Firebase Storage

By default, uploading a file to a path that already has a file silently replaces the existing file. There is no confirmation prompt and no error. This can be a problem when multiple users upload files with the same name or when you need to preserve file history. This tutorial covers three strategies: generating unique filenames, writing security rules to block overwrites, and checking existence before upload.

Prerequisites

  • A Firebase project with Cloud Storage enabled
  • Firebase JS SDK v9+ installed in your project
  • Basic understanding of Firebase Storage upload and download functions
  • Storage security rules basics

Step-by-step guide

1

Understand the default overwrite behavior

When you call uploadBytes or uploadBytesResumable with a storage reference pointing to an existing file, Firebase replaces the file entirely. The download URL changes (a new token is generated), and the old file is gone permanently. There is no versioning, no trash, and no undo. Any code or links using the old download URL will break.

typescript
1import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage'
2
3const storage = getStorage()
4
5// This OVERWRITES if 'uploads/avatar.png' already exists
6async function uploadAvatar(file: File) {
7 const storageRef = ref(storage, 'uploads/avatar.png')
8 await uploadBytes(storageRef, file)
9 const url = await getDownloadURL(storageRef)
10 // The old file at this path is gone — old download URLs are invalid
11 return url
12}

Expected result: The file at the existing path is silently replaced. No error is thrown, and the old download URL stops working.

2

Generate unique filenames to prevent accidental overwrites

The most reliable way to prevent overwrites is to ensure every upload goes to a unique path. Append a UUID, timestamp, or both to the filename. This guarantees uniqueness regardless of the original filename. Organize files in user-specific folders using the user's UID for additional isolation.

typescript
1import { ref, uploadBytes, getDownloadURL } from 'firebase/storage'
2import { v4 as uuidv4 } from 'uuid'
3
4async function uploadFile(userId: string, file: File) {
5 // Generate unique filename: userId/uuid-originalname
6 const uniqueName = `${uuidv4()}-${file.name}`
7 const storagePath = `uploads/${userId}/${uniqueName}`
8 const storageRef = ref(storage, storagePath)
9
10 const snapshot = await uploadBytes(storageRef, file, {
11 contentType: file.type,
12 customMetadata: {
13 originalName: file.name,
14 uploadedBy: userId,
15 },
16 })
17
18 const downloadURL = await getDownloadURL(snapshot.ref)
19 return { downloadURL, path: storagePath }
20}
21
22// Alternative: use timestamp
23function uniqueFilename(originalName: string): string {
24 const timestamp = Date.now()
25 const ext = originalName.split('.').pop()
26 const baseName = originalName.replace(/\.[^.]+$/, '')
27 return `${baseName}_${timestamp}.${ext}`
28 // avatar_1711612800000.png
29}

Expected result: Every upload creates a new file at a unique path, preserving all previously uploaded files.

3

Block overwrites with Storage security rules

Write a security rule that only allows uploads when no file exists at the target path. The resource variable in Storage rules refers to the existing file metadata. When resource is null, no file exists at that path. Combine this with authenticated upload checks. This is the only server-enforced way to prevent overwrites.

typescript
1// storage.rules
2rules_version = '2';
3service firebase.storage {
4 match /b/{bucket}/o {
5
6 // User uploads: only allow if file does not already exist
7 match /uploads/{userId}/{fileName} {
8 // Allow read if authenticated
9 allow read: if request.auth != null;
10
11 // Allow create ONLY — file must not exist
12 allow create: if request.auth != null
13 && request.auth.uid == userId
14 && resource == null // No existing file
15 && request.resource.size < 10 * 1024 * 1024; // Max 10MB
16
17 // Block updates and deletes
18 allow update: if false;
19 allow delete: if request.auth != null
20 && request.auth.uid == userId;
21 }
22 }
23}

Expected result: Uploads to paths where a file already exists are rejected by the security rules with a permission denied error.

4

Check file existence before uploading (client-side)

Before uploading, try to get the download URL for the target path. If it succeeds, a file already exists. If it throws a storage/object-not-found error, the path is available. This gives you a chance to warn the user before uploading. Note that this has a race condition — another user could upload between your check and your upload — so always combine it with security rules for true protection.

typescript
1import { ref, getDownloadURL, uploadBytes } from 'firebase/storage'
2
3async function uploadIfNotExists(path: string, file: File) {
4 const storageRef = ref(storage, path)
5
6 try {
7 // Check if file already exists
8 await getDownloadURL(storageRef)
9 // If we reach here, the file exists
10 throw new Error(`File already exists at ${path}`)
11 } catch (error: any) {
12 if (error.code === 'storage/object-not-found') {
13 // File does not exist — safe to upload
14 const snapshot = await uploadBytes(storageRef, file)
15 return getDownloadURL(snapshot.ref)
16 }
17 throw error // Re-throw other errors
18 }
19}
20
21// Usage
22try {
23 const url = await uploadIfNotExists('uploads/report.pdf', file)
24 console.log('Uploaded:', url)
25} catch (error: any) {
26 if (error.message.includes('already exists')) {
27 console.log('File exists — ask user to rename or confirm overwrite')
28 }
29}

Expected result: The client detects existing files before uploading and can prompt the user to choose a different name.

5

Implement versioned uploads with a Firestore metadata log

For applications that need file versioning (like document management), upload each version to a unique path and store all versions in a Firestore document. This preserves every version and lets users download or restore any previous upload. Use a Firestore array or subcollection to track the version history.

typescript
1import { doc, updateDoc, arrayUnion, serverTimestamp } from 'firebase/firestore'
2import { ref, uploadBytes, getDownloadURL } from 'firebase/storage'
3
4async function uploadNewVersion(
5 userId: string,
6 fileGroupId: string,
7 file: File
8) {
9 const version = Date.now()
10 const storagePath = `files/${userId}/${fileGroupId}/v${version}-${file.name}`
11 const storageRef = ref(storage, storagePath)
12
13 // Upload the file
14 const snapshot = await uploadBytes(storageRef, file)
15 const downloadURL = await getDownloadURL(snapshot.ref)
16
17 // Log the version in Firestore
18 await updateDoc(doc(db, 'file_groups', fileGroupId), {
19 currentVersion: {
20 url: downloadURL,
21 path: storagePath,
22 uploadedAt: serverTimestamp(),
23 size: file.size,
24 },
25 versions: arrayUnion({
26 url: downloadURL,
27 path: storagePath,
28 version,
29 size: file.size,
30 name: file.name,
31 }),
32 })
33
34 return downloadURL
35}

Expected result: Each upload creates a new version at a unique path while Firestore maintains a complete version history.

Complete working example

storage-no-overwrite.ts
1import { initializeApp } from 'firebase/app'
2import {
3 getStorage,
4 ref,
5 uploadBytes,
6 getDownloadURL,
7} from 'firebase/storage'
8import { v4 as uuidv4 } from 'uuid'
9
10const app = initializeApp({
11 apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
12 authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN!,
13 projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
14 storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET!,
15})
16
17const storage = getStorage(app)
18
19export function generateUniquePath(userId: string, fileName: string): string {
20 const ext = fileName.split('.').pop() ?? ''
21 return `uploads/${userId}/${uuidv4()}.${ext}`
22}
23
24export async function uploadWithUniqueId(
25 userId: string,
26 file: File
27): Promise<{ url: string; path: string }> {
28 const path = generateUniquePath(userId, file.name)
29 const storageRef = ref(storage, path)
30 const snapshot = await uploadBytes(storageRef, file, {
31 contentType: file.type,
32 customMetadata: { originalName: file.name },
33 })
34 const url = await getDownloadURL(snapshot.ref)
35 return { url, path }
36}
37
38export async function fileExists(path: string): Promise<boolean> {
39 try {
40 await getDownloadURL(ref(storage, path))
41 return true
42 } catch (err: any) {
43 if (err.code === 'storage/object-not-found') return false
44 throw err
45 }
46}
47
48export async function safeUpload(
49 path: string,
50 file: File
51): Promise<string> {
52 if (await fileExists(path)) {
53 throw new Error('File already exists. Choose a different name.')
54 }
55 const snapshot = await uploadBytes(ref(storage, path), file)
56 return getDownloadURL(snapshot.ref)
57}

Common mistakes when preventing File Overwrite in Firebase Storage

Why it's a problem: Assuming Firebase Storage will throw an error when uploading to an existing path

How to avoid: It will not. Firebase silently overwrites the file. Always use unique filenames or security rules to prevent this.

Why it's a problem: Relying only on the client-side existence check without security rules, leaving a race condition

How to avoid: Another client can upload between your getDownloadURL check and your uploadBytes call. Use security rules with resource == null for server-enforced protection.

Why it's a problem: Using the user-provided filename directly as the storage path, leading to conflicts when users upload files with common names like 'image.png'

How to avoid: Always append a UUID or timestamp to the filename, or use the user's UID as a folder prefix, or both.

Best practices

  • Generate unique filenames with UUID or timestamp for every upload to prevent accidental overwrites
  • Organize uploads in user-specific folders using the UID: uploads/{userId}/{filename}
  • Write Storage security rules with resource == null to enforce create-only uploads at the server level
  • Store the original filename in customMetadata so it can be displayed to users later
  • Combine client-side existence checks (for UX) with security rules (for enforcement)
  • For file versioning, upload each version to a unique path and track versions in Firestore
  • Set file size limits in both security rules (request.resource.size) and client-side validation

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Firebase Storage silently overwrites files when I upload to an existing path. Show me how to prevent this using three approaches: generating unique filenames with UUID, writing Storage security rules that block overwrites, and checking file existence before uploading. Use Firebase JS SDK v9.

Firebase Prompt

Add file upload to this app that prevents overwriting existing files. Generate a unique filename with UUID for each upload, store the original name in metadata, and write Storage security rules with resource == null to block overwrites at the server level.

Frequently asked questions

Does Firebase Storage have file versioning?

No. Firebase Storage does not have built-in file versioning. Uploading to the same path replaces the file permanently. To keep versions, upload each version to a unique path and track them in Firestore.

What happens to the old download URL when a file is overwritten?

The old download URL stops working because it contains a token that is invalidated when the file is replaced. A new token and URL are generated for the replacement file.

Can I recover an overwritten file?

No. Once a file is overwritten, the previous version is permanently deleted. There is no trash or undo feature. Enable Google Cloud Storage object versioning on the underlying GCS bucket for recovery (requires Blaze plan and GCS console access).

Is the UUID approach better than the timestamp approach?

UUIDs are guaranteed unique regardless of timing, while timestamps can collide if two users upload in the same millisecond. Use UUID for maximum safety. Timestamps are acceptable when combined with user-specific folders.

Do security rules prevent overwriting even from the Admin SDK?

No. The Admin SDK bypasses all security rules. Security rules only apply to client SDK operations. For server-side overwrite prevention, check existence in your Cloud Function code before uploading.

Can RapidDev help set up secure file uploads in my Firebase app?

Yes. RapidDev can implement secure file upload systems with unique naming, overwrite prevention, file versioning, and proper security rules for your specific requirements.

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.