Handling File Uploads in Next.js with Firebase Storage

Thursday, January 30, 2025

Uploading files is a common feature in modern web applications, whether for profile pictures, document storage, or media sharing. Firebase Storage offers a scalable and secure way to handle file uploads, making it a great choice for Next.js applications.

In this guide, we’ll walk through setting up Firebase Storage, integrating it with a Next.js app, and implementing a file upload system.


Setting Up Firebase Storage

Before integrating Firebase Storage in our Next.js app, we need to set it up in Firebase.

Step 1: Create a Firebase Project

  • Go to Firebase Console.
  • Click "Add project" and follow the setup instructions.
  • Once created, navigate to the Build > Storage section in the Firebase dashboard.
  • Step 2: Enable Firebase Storage

  • In the Firebase console, go to Storage and click "Get Started."
  • Choose a storage location and confirm settings.
  • Set default storage rules (we’ll update them later).
  • Step 3: Get Firebase Config for Next.js

  • Navigate to Project settings > General > Your apps.
  • Click on the Web option to register an app.
  • Copy the Firebase config object for later use.

  • Installing Firebase SDK in Next.js

    Run the following command in your Next.js project to install Firebase:

    Language: bash
    npm install firebase

    Now, create a Firebase configuration file to initialize Firebase in your project.

    Language: javascript
    // firebaseConfig.js
    import { initializeApp } from "firebase/app";
    import { getStorage } from "firebase/storage";
    
    const firebaseConfig = {
      apiKey: "YOUR_API_KEY",
      authDomain: "YOUR_AUTH_DOMAIN",
      projectId: "YOUR_PROJECT_ID",
      storageBucket: "YOUR_STORAGE_BUCKET",
      messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
      appId: "YOUR_APP_ID",
    };
    
    const app = initializeApp(firebaseConfig);
    const storage = getStorage(app);
    
    export { storage };

    Creating the Upload Form in Next.js

    Now, let's create a file upload form.

    Language: javascript
    import { useState } from "react";
    
    export default function FileUpload({ onFileSelect }) {
      const [file, setFile] = useState(null);
    
      const handleFileChange = (event) => {
        setFile(event.target.files[0]);
      };
    
      const handleSubmit = (event) => {
        event.preventDefault();
        if (file) {
          onFileSelect(file);
        }
      };
    
      return (
        <form onSubmit={handleSubmit} className="space-y-4">
          <input type="file" onChange={handleFileChange} />
          <button type="submit">Upload</button>
        </form>
      );
    }

    This component allows users to select a file and trigger the upload function.


    Uploading Files to Firebase Storage

    Now, let's create a function to upload files to Firebase Storage.

    Language: javascript
    import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
    import { storage } from "../firebaseConfig";
    
    export function uploadFile(file, onProgress, onComplete, onError) {
      const storageRef = ref(storage, `uploads/${file.name}`);
      const uploadTask = uploadBytesResumable(storageRef, file);
    
      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const progress =
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          onProgress(progress);
        },
        (error) => {
          onError(error);
        },
        async () => {
          const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
          onComplete(downloadURL);
        }
      );
    }

    Retrieving and Displaying Uploaded Files

    Once the upload is complete, we can display the uploaded files using their download URLs.

    Language: javascript
    import { useState } from "react";
    import { uploadFile } from "../utils/uploadFile";
    
    export default function UploadComponent() {
      const [progress, setProgress] = useState(0);
      const [fileURL, setFileURL] = useState("");
    
      const handleFileUpload = (file) => {
        uploadFile(
          file,
          (progress) => setProgress(progress),
          (url) => setFileURL(url),
          (error) => console.error("Upload error:", error)
        );
      };
    
      return (
        <div>
          <h2>Upload a File</h2>
          <FileUpload onFileSelect={handleFileUpload} />
          {progress > 0 && <p>Upload Progress: {progress}%</p>}
          {fileURL && <img src={fileURL} alt="Uploaded File" />}
        </div>
      );
    }

    Securing File Access

    By default, Firebase Storage allows public access, which is not ideal for sensitive files. Update your storage rules to allow only authenticated users to upload and access their files:

  • Go to Storage > Rules in the Firebase Console.
  • Replace the default rules with:
  • Language: json
    rules_version = '2';
    service firebase.storage {
      match /b/{bucket}/o {
        match /uploads/{userId}/{file} {
          allow read, write: if request.auth != null && request.auth.uid == userId;
        }
      }
    }
    

    This ensures that only authenticated users can access their files.


    Conclusion

    In this tutorial, we covered:

    ✅ Setting up Firebase Storage

    ✅ Integrating Firebase Storage with a Next.js app

    ✅ Handling file uploads and tracking progress

    ✅ Displaying uploaded files

    ✅ Securing file access with Firebase rules

    With these basics in place, you can enhance the upload experience by adding features like multiple file uploads, drag-and-drop support, or file previews. 🚀