Paramclasses Academy - Blog

Tutorials Details

←
Post 31 of 39
→

How to upload Upload Images and Files to Firebase Storage from React Native ?

How to upload Upload Images and Files to Firebase Storage from React Native ?

November 5, 2026

1. Introduction

Mobile applications frequently need to upload images, PDFs, documents, and other files to cloud storage.

For example:

  • A student app uploads profile pictures.

  • An e-commerce app uploads product images.

  • A chat application shares photos and documents.

  • A learning application uploads PDF study materials.

Firebase Cloud Storage provides cloud-based file storage that can be accessed from mobile applications.

In this tutorial, we will use:

  • React Native with Expo.

  • Firebase Cloud Storage.

  • Expo Image Picker.

  • Expo Document Picker.

  • Firebase JavaScript SDK.

2. What Is Firebase Cloud Storage?

Firebase Cloud Storage is a cloud storage service designed to store and serve user-generated files such as images, videos, audio, and documents.

Unlike Cloud Firestore, which stores structured application data, Cloud Storage stores actual files.

Cloud Storage Structure

Firebase Storage
│
├── images/
│   ├── profile_001.jpg
│   ├── product_001.png
│   └── student_001.jpg
│
├── documents/
│   ├── notes.pdf
│   ├── assignment.pdf
│   └── resume.pdf
│
└── videos/
    └── tutorial.mp4

3. Features of Firebase Storage

  1. Cloud File Storage: Store images, PDFs, videos, and other files.

  2. File Upload: Upload files directly from mobile applications.

  3. Download URLs: Generate URLs to access uploaded files.

  4. Security Rules: Control access to stored files.

  5. File Metadata: Store file names, MIME types, and other metadata.

  6. Scalable Infrastructure: Use Google Cloud Storage infrastructure.

  7. Firebase Integration: Integrate with Firebase Authentication and other Firebase services.

4. What We Will Build

We will create a practical application called Firebase File Upload App.

The app will include:

  • Select an image from the gallery.

  • Select a document from the device.

  • Preview the selected image.

  • Display the selected file name.

  • Upload images to Firebase Storage.

  • Upload documents to Firebase Storage.

  • Generate download URLs.

  • Display uploaded images.

  • Open uploaded files.

Application Workflow

Open React Native App
        |
        v
Select Image or Document
        |
        v
Preview Selected File
        |
        v
Press Upload Button
        |
        v
Firebase Cloud Storage
        |
        v
Generate Download URL
        |
        v
Display Uploaded File

5. Requirements

Before starting, make sure you have:

  • Node.js and npm installed.

  • Expo development environment configured.

  • Android Studio or Expo Go.

  • A Firebase account.

  • Basic React Native knowledge.

  • A Firebase project from the previous tutorial, or a new project.

Important Firebase billing update: As of November 2026, Cloud Storage for Firebase requires the Blaze pay-as-you-go plan to create and access Storage buckets. No-cost usage quotas may still apply, but additional usage can incur charges. Set up budget alerts before uploading files.

Firebase+2

6. Create a React Native Project

Open your terminal:

npx create-expo-app@latest FirebaseFileUpload --template blank

Navigate to the project:

cd FirebaseFileUpload

Start the application:

npx expo start

7. Install Required Packages

Install Firebase:

npx expo install firebase

Install Expo Image Picker:

npx expo install expo-image-picker

Install Expo Document Picker:

npx expo install expo-document-picker

These packages allow us to select images and documents from the device.

Official documentation:

8. Create a Firebase Project

If you already created a Firebase project in Tutorial 31, you can use the same project.

Otherwise:

  1. Open Firebase Console.

  2. Click Create a Project.

  3. Enter the project name.

  4. Complete project setup.

  5. Register a Web App.

  6. Copy the Firebase configuration.

Firebase Console:

https://console.firebase.google.com/

9. Enable Firebase Cloud Storage

Follow these steps:

  1. Open your Firebase project.

  2. Navigate to Databases & Storage → Storage.

  3. Upgrade to the Blaze plan if prompted.

  4. Click Get Started.

  5. Select a Storage bucket location.

  6. Review the initial security rules.

  7. Complete the setup.

Your Firebase Storage bucket is now ready.

Note: New default buckets generally use the PROJECT_ID.firebasestorage.app naming format. Older projects may have an appspot.com bucket. Always copy the actual bucket name from your Firebase Console.

Firebase+1

10. Configure Firebase in React Native

Create a file named:

firebaseConfig.js

Add the following code:

import { initializeApp } from "firebase/app";
import { getStorage } from "firebase/storage";

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_ACTUAL_BUCKET_NAME",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID",
};

const app = initializeApp(firebaseConfig);

const storage = getStorage(app);

export { storage };

Replace all placeholder values with your Firebase project configuration.

The getStorage() function initializes the Cloud Storage service.

11. Understand Important Firebase Storage Functions

Function

Purpose

getStorage()

Initializes Firebase Storage

ref()

Creates a reference to a storage location

uploadBytes()

Uploads file data

getDownloadURL()

Retrieves a downloadable URL

deleteObject()

Deletes a stored file

getMetadata()

Retrieves file metadata

 

 

 

These functions are provided by the modular Firebase JavaScript SDK.

12. Understand Image Picker

Expo Image Picker allows users to select images from their device's media library.

Example:

import * as ImagePicker from "expo-image-picker";

const pickImage = async () => {
  const result =
    await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ["images"],
      allowsEditing: true,
      quality: 0.8,
    });

  if (!result.canceled) {
    console.log(result.assets[0].uri);
  }
};

The selected image URI identifies the local image file.

13. Understand Document Picker

Expo Document Picker allows users to select files such as PDF documents.

Example:

import * as DocumentPicker from "expo-document-picker";

const pickDocument = async () => {
  const result =
    await DocumentPicker.getDocumentAsync({
      type: "*/*",
      copyToCacheDirectory: true,
    });

  if (!result.canceled) {
    console.log(result.assets[0].name);
    console.log(result.assets[0].uri);
  }
};

The selected asset contains information such as its file name, URI, and MIME type.

Setting copyToCacheDirectory: true makes the selected file available in the app's cache for immediate reading.

Expo documentation+1

14. Convert a Local File into a Blob

The Firebase JavaScript SDK's uploadBytes() function accepts a Blob, File, or byte array.

In our Expo application, we can convert a selected local file URI into a Blob using fetch():

const response = await fetch(fileUri);

const blob = await response.blob();

We can then upload this Blob to Firebase Storage.

This technique is useful for uploading both selected images and documents.

15. Create the Main Application

Our application will have:

  • Image selection button.

  • Document selection button.

  • Selected file preview.

  • Upload button.

  • Uploaded images section.

  • Uploaded documents section.

  • Delete file option.

Create or open App.js.

Complete App.js Code

import React, { useState } from "react";

import {
  View,
  Text,
  Pressable,
  Image,
  FlatList,
  StyleSheet,
  Alert,
  ActivityIndicator,
  Linking,
  ScrollView,
} from "react-native";

import * as ImagePicker from "expo-image-picker";
import * as DocumentPicker from "expo-document-picker";

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

import { storage } from "./firebaseConfig";

export default function App() {
  const [selectedFile, setSelectedFile] = useState(null);

  const [uploadedFiles, setUploadedFiles] = useState([]);

  const [uploading, setUploading] = useState(false);

  // Select image from gallery
  const pickImage = async () => {
    try {
      const result =
        await ImagePicker.launchImageLibraryAsync({
          mediaTypes: ["images"],
          allowsEditing: true,
          quality: 0.8,
        });

      if (!result.canceled) {
        const asset = result.assets[0];

        setSelectedFile({
          uri: asset.uri,
          name: asset.fileName || `image_${Date.now()}.jpg`,
          mimeType: asset.mimeType || "image/jpeg",
          type: "image",
        });
      }
    } catch (error) {
      Alert.alert("Error", "Unable to select image.");
    }
  };

  // Select document
  const pickDocument = async () => {
    try {
      const result =
        await DocumentPicker.getDocumentAsync({
          type: "*/*",
          copyToCacheDirectory: true,
        });

      if (!result.canceled) {
        const asset = result.assets[0];

        setSelectedFile({
          uri: asset.uri,
          name: asset.name,
          mimeType:
            asset.mimeType || "application/octet-stream",
          type: "document",
        });
      }
    } catch (error) {
      Alert.alert("Error", "Unable to select document.");
    }
  };

  // Upload file to Firebase Storage
  const uploadFile = async () => {
    if (!selectedFile) {
      Alert.alert("Error", "Please select a file first.");
      return;
    }

    try {
      setUploading(true);

      const response = await fetch(selectedFile.uri);

      if (!response.ok) {
        throw new Error("Unable to read selected file.");
      }

      const blob = await response.blob();

      const filePath =
        `${selectedFile.type}s/${Date.now()}_${selectedFile.name}`;

      const storageRef = ref(storage, filePath);

      const uploadResult = await uploadBytes(
        storageRef,
        blob,
        {
          contentType: selectedFile.mimeType,
        }
      );

      const downloadURL =
        await getDownloadURL(uploadResult.ref);

      const uploadedFile = {
        id: filePath,
        name: selectedFile.name,
        url: downloadURL,
        type: selectedFile.type,
      };

      setUploadedFiles((previous) => [
        uploadedFile,
        ...previous,
      ]);

      setSelectedFile(null);

      Alert.alert(
        "Success",
        "File uploaded successfully!"
      );

    } catch (error) {
      console.error("Upload Error:", error);

      Alert.alert(
        "Upload Failed",
        error.message || "Unable to upload file."
      );

    } finally {
      setUploading(false);
    }
  };

  // Open uploaded file
  const openFile = async (url) => {
    try {
      await Linking.openURL(url);
    } catch (error) {
      Alert.alert("Error", "Unable to open file.");
    }
  };

  // Delete uploaded file
  const removeFile = async (file) => {
    Alert.alert(
      "Delete File",
      "Are you sure you want to delete this file?",
      [
        {
          text: "Cancel",
          style: "cancel",
        },
        {
          text: "Delete",
          style: "destructive",
          onPress: async () => {
            try {
              await deleteObject(
                ref(storage, file.id)
              );

              setUploadedFiles((previous) =>
                previous.filter(
                  (item) => item.id !== file.id
                )
              );

              Alert.alert(
                "Success",
                "File deleted successfully."
              );

            } catch (error) {
              console.error("Delete Error:", error);

              Alert.alert(
                "Error",
                "Unable to delete file."
              );
            }
          },
        },
      ]
    );
  };

  // Render uploaded files
  const renderFile = ({ item }) => (
    <View style={styles.fileCard}>
      {item.type === "image" ? (
        <Image
          source={{ uri: item.url }}
          style={styles.uploadedImage}
        />
      ) : (
        <Text style={styles.documentIcon}>
          ????
        </Text>
      )}

      <Text
        style={styles.fileName}
        numberOfLines={2}
      >
        {item.name}
      </Text>

      <View style={styles.actionRow}>
        <Pressable
          style={styles.openButton}
          onPress={() => openFile(item.url)}
        >
          <Text style={styles.buttonText}>
            Open
          </Text>
        </Pressable>

        <Pressable
          style={styles.deleteButton}
          onPress={() => removeFile(item)}
        >
          <Text style={styles.buttonText}>
            Delete
          </Text>
        </Pressable>
      </View>
    </View>
  );

  return (
    <ScrollView
      style={styles.container}
      contentContainerStyle={styles.content}
    >
      <Text style={styles.heading}>
        Firebase File Upload
      </Text>

      <Text style={styles.subtitle}>
        Upload Images and Documents to Cloud Storage
      </Text>

      <View style={styles.selectionBox}>
        <Text style={styles.sectionTitle}>
          Select Your File
        </Text>

        <Pressable
          style={styles.imageButton}
          onPress={pickImage}
        >
          <Text style={styles.buttonText}>
            Select Image
          </Text>
        </Pressable>

        <Pressable
          style={styles.documentButton}
          onPress={pickDocument}
        >
          <Text style={styles.buttonText}>
            Select Document
          </Text>
        </Pressable>
      </View>

      {selectedFile && (
        <View style={styles.previewBox}>
          <Text style={styles.sectionTitle}>
            Selected File
          </Text>

          {selectedFile.type === "image" ? (
            <Image
              source={{ uri: selectedFile.uri }}
              style={styles.previewImage}
            />
          ) : (
            <Text style={styles.documentIcon}>
              ????
            </Text>
          )}

          <Text style={styles.fileName}>
            {selectedFile.name}
          </Text>

          <Pressable
            style={styles.uploadButton}
            onPress={uploadFile}
            disabled={uploading}
          >
            {uploading ? (
              <ActivityIndicator color="#FFFFFF" />
            ) : (
              <Text style={styles.buttonText}>
                Upload to Firebase
              </Text>
            )}
          </Pressable>
        </View>
      )}

      <Text style={styles.sectionTitle}>
        Uploaded Files ({uploadedFiles.length})
      </Text>

      <FlatList
        data={uploadedFiles}
        keyExtractor={(item) => item.id}
        renderItem={renderFile}
        scrollEnabled={false}
        ListEmptyComponent={
          <Text style={styles.emptyText}>
            No files uploaded yet.
          </Text>
        }
      />
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#F1F5F9",
  },

  content: {
    padding: 20,
    paddingTop: 60,
    paddingBottom: 40,
  },

  heading: {
    fontSize: 25,
    fontWeight: "bold",
    color: "#172554",
  },

  subtitle: {
    fontSize: 13,
    color: "#64748B",
    marginBottom: 25,
  },

  selectionBox: {
    backgroundColor: "#FFFFFF",
    padding: 18,
    borderRadius: 14,
    marginBottom: 20,
  },

  sectionTitle: {
    fontSize: 18,
    fontWeight: "bold",
    color: "#1E293B",
    marginBottom: 15,
  },

  imageButton: {
    backgroundColor: "#2563EB",
    padding: 15,
    borderRadius: 9,
    alignItems: "center",
    marginBottom: 12,
  },

  documentButton: {
    backgroundColor: "#7C3AED",
    padding: 15,
    borderRadius: 9,
    alignItems: "center",
  },

  previewBox: {
    backgroundColor: "#FFFFFF",
    padding: 18,
    borderRadius: 14,
    marginBottom: 25,
    alignItems: "center",
  },

  previewImage: {
    width: 220,
    height: 180,
    borderRadius: 12,
    resizeMode: "cover",
    marginBottom: 12,
  },

  documentIcon: {
    fontSize: 65,
    marginBottom: 10,
  },

  fileName: {
    fontSize: 14,
    color: "#334155",
    marginVertical: 10,
    textAlign: "center",
  },

  uploadButton: {
    backgroundColor: "#059669",
    padding: 15,
    borderRadius: 9,
    alignItems: "center",
    width: "100%",
    marginTop: 10,
  },

  buttonText: {
    color: "#FFFFFF",
    fontWeight: "bold",
  },

  fileCard: {
    backgroundColor: "#FFFFFF",
    padding: 15,
    borderRadius: 12,
    marginBottom: 12,
  },

  uploadedImage: {
    width: "100%",
    height: 160,
    borderRadius: 10,
  },

  actionRow: {
    flexDirection: "row",
    gap: 10,
    marginTop: 10,
  },

  openButton: {
    backgroundColor: "#2563EB",
    padding: 10,
    borderRadius: 7,
    flex: 1,
    alignItems: "center",
  },

  deleteButton: {
    backgroundColor: "#DC2626",
    padding: 10,
    borderRadius: 7,
    flex: 1,
    alignItems: "center",
  },

  emptyText: {
    color: "#64748B",
    textAlign: "center",
    marginTop: 15,
  },
});

16. Understand the File Upload Process

Let's understand the most important part of our application.

Step 1: Create a Storage Reference

const storageRef = ref(
  storage,
  "images/my-photo.jpg"
);

The ref() function creates a reference to the file's destination in Firebase Storage.

Step 2: Convert the Selected File into a Blob

const response = await fetch(selectedFile.uri);

const blob = await response.blob();

This reads the selected local file and converts it into a Blob.

Step 3: Upload the File

const uploadResult = await uploadBytes(
  storageRef,
  blob,
  {
    contentType: selectedFile.mimeType,
  }
);

The uploadBytes() function uploads the file to the specified Storage reference.

Step 4: Generate the Download URL

const downloadURL = await getDownloadURL(
  uploadResult.ref
);

The getDownloadURL() function returns a URL that can be used to access the uploaded file, subject to its access and token configuration.

These upload and download patterns follow Firebase's official Storage SDK documentation.

Firebase+1

17. Understand Firebase Storage Folders

Our application creates separate paths for images and documents.

const filePath =
  `${selectedFile.type}s/${Date.now()}_${selectedFile.name}`;

Example:

images/
    1730000000000_profile.jpg

documents/
    1730000000000_notes.pdf

Firebase Storage uses object paths rather than traditional folders. The console displays these paths in a folder-like structure.

18. Display Uploaded Images

React Native provides the Image component to display an image from a remote URL.

<Image
  source={{ uri: downloadURL }}
  style={{
    width: 200,
    height: 200,
  }}
/>

The download URL returned by Firebase can be used as the image source.

19. Delete Uploaded Files

Firebase provides the deleteObject() function.

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

const fileRef = ref(storage, filePath);

await deleteObject(fileRef);

This removes the specified object from Firebase Storage, provided the current user has permission.

20. Configure Firebase Storage Security Rules

Security Rules control who can upload, read, and delete files.

For an authenticated application, a basic rule can look like this:

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {

    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }

  }
}

This example permits authenticated users to access files. For production, add user-specific paths, ownership checks, file size limits, and MIME type validation.

For example, to restrict image uploads to 5 MB:

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {

    match /images/{fileName} {
      allow read: if request.auth != null;

      allow write: if request.auth != null
        && request.resource.size < 5 * 1024 * 1024
        && request.resource.contentType.matches('image/.*');
    }

  }
}

Do not use public read/write access for private user files. Firebase's security documentation explains how to validate file size, MIME type, and authorization.

Firebase+1

21. Test the Application

Follow these steps:

  1. Start the Expo development server.

  2. Open the app on your Android device.

  3. Press Select Image.

  4. Choose an image from the gallery.

  5. Check the image preview.

  6. Press Upload to Firebase.

  7. Open Firebase Console.

  8. Navigate to Storage.

  9. Open the images folder.

  10. Verify the uploaded image.

  11. Return to the app.

  12. Select a PDF document.

  13. Upload the document.

  14. Open the documents folder in Firebase Console.

  15. Verify that the document has been uploaded.

  16. Test the Open and Delete buttons.

Expected Result

The application should successfully upload selected images and documents to Firebase Storage and display the uploaded files in the interface.

22. Common Errors and Solutions

Error

Solution

Storage permission denied

Check Firebase Storage Security Rules

Storage bucket not found

Verify the storageBucket configuration

Upload failed

Check internet connectivity and billing

Image preview not working

Verify the selected file URI

Document not opening

Check the file URL and MIME type

Firebase Storage unauthorized

Verify authentication and Storage Rules

402 or 403 Storage error

Check Blaze billing configuration

 

 
   
   
   
   
   
   
   

23. Best Practices

  1. Validate file types before uploading.

  2. Restrict maximum file sizes.

  3. Use unique file names.

  4. Organize files using meaningful Storage paths.

  5. Apply Firebase Storage Security Rules.

  6. Use authentication for private files.

  7. Handle upload errors properly.

  8. Display upload progress in production applications.

  9. Avoid uploading unnecessary large files.

  10. Monitor Firebase Storage usage and billing.

Production improvement: The sample app stores uploaded file information in React state, so its uploaded-file list is temporary and resets when the app restarts. For a production app, save file metadata and download URLs in Cloud Firestore, then retrieve them when the application opens.

24. Advantages of Firebase Storage

  • Easy integration with React Native.

  • Supports images, videos, and documents.

  • Cloud-based file storage.

  • Download URL generation.

  • Firebase Authentication integration.

  • Flexible access control.

  • Suitable for media-heavy applications.

25. Conclusion

In this tutorial, we learned how to upload images and documents from a React Native application to Firebase Cloud Storage.

We created a practical File Upload App and implemented:

  • Image selection using Expo Image Picker.

  • Document selection using Expo Document Picker.

  • File preview.

  • Blob conversion.

  • Firebase Storage upload.

  • Download URL generation.

  • Uploaded file display.

  • File opening and deletion.

  • Storage Security Rules.

Firebase Storage is a useful solution for applications that need reliable cloud-based file storage.

By combining React Native, Expo, and Firebase Storage, developers can build applications that allow users to upload, store, and access files from different devices.

26. Frequently Asked Questions

Q1. What is Firebase Cloud Storage?

Firebase Cloud Storage is a cloud-based service for storing and serving files such as images, videos, and documents.

Q2. Can React Native upload images to Firebase Storage?

Yes. React Native can use the Firebase JavaScript SDK to upload images to Firebase Storage.

Q3. What is Expo Image Picker?

Expo Image Picker is a library that allows users to select images and videos from their device's media library.

Q4. What is Expo Document Picker?

Expo Document Picker allows users to select documents and other files from their device.

Q5. What does uploadBytes() do?

It uploads Blob, File, or byte-array data to a Firebase Storage reference.

Q6. What does getDownloadURL() do?

It retrieves a download URL for an uploaded Storage object.

Q7. Can Firebase Storage store PDF files?

Yes. Firebase Storage supports PDFs and many other file types.

Q8. Is Firebase Storage free?

Cloud Storage for Firebase currently requires the Blaze plan. Applicable no-cost quotas may be available, but usage beyond those quotas can incur charges.

Official Documentation

  1. Firebase Cloud Storage: https://firebase.google.com/docs/storage

  2. Firebase Storage Setup: https://firebase.google.com/docs/storage/web/start

  3. Upload Files: https://firebase.google.com/docs/storage/web/upload-files

  4. Download Files: https://firebase.google.com/docs/storage/web/download-files

  5. Storage Security Rules: https://firebase.google.com/docs/storage/security

  6. Expo Image Picker: https://docs.expo.dev/versions/latest/sdk/imagepicker/

  7. Expo Document Picker: https://docs.expo.dev/versions/latest/sdk/document-picker/

  8. Firebase Pricing: https://firebase.google.com/pricing

←
Post 31 of 39
→