Cloud Storage can be real frustrating if you don’t know what you’re doing. Thankfully, Firebase simplifies it down to as simple as it can be. We’ll go over why you’d want to use Firebase Cloud Storage over other cloud storage services, and the different ways to go about it.

As with my other tutorials, this will be a very simplified version of using Firebase Cloud Storage. For a more comprehensive tutorial, check out the official docs.


Before you can use Firebase Cloud Storage, you need to have the Firebase SDK installed. Check out how to do this in a couple minutes using the Firebase Assistant.

You’ll also have to go to your console, set up a new project there if you haven’t already (or do it when connecting your app to Firebase with the Assistant), and intialise Cloud Storage there. It will default security rules to only allow authenticated users, but if you change it to this, it will allow all users access to the storage (make sure to change it later though).

Why use Firebase Cloud Storage?

Robust Operations

Larger upload and download operations can take time, especially for users of weaker internet connections. If network connection fails mid-operation, your operation will continue where it previously stopped.

Strong Security

You can configure security rules to only allow operations to be performed under certain conditions which you can also integrate with Firebase Authentication.

High Scalability

When your app starts going viral and more operations are being conducted, your storage can easily scale up to handle wider audiences… with a bit of money of course. You can’t get everything free.

Integrating Cloud Storage into your App

To use Firebase Cloud Storage, you’ll have to get an instance of  Firebase Storage , get a reference which points to a location in the online storage bucket, then from there you can perform upload and download operations.

First, add this dependency to your app-level  build.gradle file.

Getting our Reference

First, get an instance of Firebase Storage.

Next, just like with the Realtime Database or Firestore, we’ll get a reference to the root of our storage directory.

Then just like in the databases, you can go lower in the tree with

Extra Navigation

As with the databases again, you have the methods  getParent and  getRoot for up navigation.

Uploading Files to your Storage Reference

So far, we’ve treated our references like directories. With storage however, unlike the Firebase Databases, the references can point to a file’s location as well. I’ll show you what I mean.

When we upload a file to this ref, regardless of its original filename, it will be uploaded to the cloud storage as images/myimagedirectory/mountains.jpg. If we upload another file to this same reference, the new file will override the previously uploaded file.

Now that we have our file reference, we’ll now look at different ways to upload a file into this reference.


This method is the simplest way to upload a file that takes in a  byte[] and returns an  UploadTask which you can use to manage and monitor the status of the upload.

In this example. we got the data from an  ImageView as a  byte[] and attached success and failure listeners to the  UploadTask to properly handle the operation when it finishes.

The downside with  putBytes() is it’s memory-intensive because it requires your app to hold the entire contents of your file in memory at once. The other 2 methods we’ll cover here are better if you want to use less memory.


This is the most versatile method to upload to cloud storage. It takes in an  InputStream and again, returns an  UploadTask .

In this example, we’re getting a  FileInputStream from a directory in our local phone storage and passing it into  putStream to get an  UploadTask .


This method takes a file’s  Uri and once again returns an  UploadTask

In this example, we’re getting a  Uri from a file in our local storage and we’re passing it into  putFile to get an  UploadTask .

Downloading Files from your StorageReference

Just like with uploading, you start by getting a reference to the file you want to download. Once you got that, you can use one of 2 methods, all similar to the ones used to upload files. Both methods will return a  DownloadTask which you can attach success and failure listeners to.


This is the easiest way to download files. It does have several drawbacks though. It’s more memory-intensive, and if you request a file that takes up more space than your app’s available memory, your app will crash.

To prevent this from happening, we pass a maximum amount of bytes we want to download into  getBytes . Set this maximum to a number you know your app can handle, or use a different download method.


This method downloads a file directly into your device’s local storage. This means that the file can then be accessed offline or shared with another app once downloaded.

In case you were wondering, there is a getStream method, however I’m not great at dealing with input streams and bitmaps. If anyone knows how to do this, please leave it as a comment! It would certainly help others here as well.

Handling Errors

There are many errors that can stem from a download task, such as the file not existing or the user not having permission to access that file. Be sure to handle these errors appropriately in your  OnFailureListener on your  DownloadTask .

Get the Example App Source Code

As with my other tutorials, I prepared an example app for you here. This app has all the download and upload methods mentioned in this article which you can switch through by commenting and uncommenting the used methods. I certainly do hope it helps!