Firebase Storage in Flutter
Firebase Storage, also known as Cloud Storage for Firebase, provides secure and scalable object storage for Flutter applications. It is commonly used to store user-generated files such as profile images, product images, documents, audio files, videos, and other media. Flutter applications can upload files to Firebase Storage, retrieve download URLs, display or download files, read metadata, and delete files using the firebase_storage package.
For official Firebase and Flutter learning resources, visit JustAcademy Flutter Training Course and Register for Flutter Course Demo.
1. What is Firebase Storage?
Firebase Storage is a cloud-based object storage service built on Google Cloud infrastructure. It allows Flutter applications to upload and retrieve files directly from cloud storage.
Typical files stored in Firebase Storage include:
- Other user-generated media
2. Why Use Firebase Storage with Flutter?
- Easy integration with Flutter.
- Supports images, videos, documents, audio, and other files.
- Provides scalable cloud storage.
- Supports upload and download operations.
- Works with Firebase Authentication and Security Rules.
- Provides resumable upload capabilities.
- Can be integrated with Firestore to store file information.
3. Firebase Storage Architecture
A typical Flutter application can use Firebase Storage together with Firebase Authentication and Cloud Firestore.
Flutter App
|
|-- Firebase Authentication
| |
| |-- User identity
|
|-- Firebase Storage
| |
| |-- Images
| |-- Videos
| |-- Documents
| |-- Audio
|
|-- Cloud Firestore
|
|-- File metadata
|-- User information
|-- File URLs
Firebase Storage stores the actual files, while Firestore can store related application data such as file names, download URLs, user IDs, categories, and timestamps.
4. Firebase Storage vs Firestore
| Firebase Storage |
Cloud Firestore |
| Stores files and media |
Stores structured application data |
| Images, videos, PDFs, audio |
Strings, numbers, objects, arrays, timestamps |
| Object storage |
NoSQL document database |
| Uses storage references |
Uses collections and documents |
| Can generate download URLs |
Can store those URLs as document fields |
5. Prerequisites
Before using Firebase Storage in Flutter, you should have:
- Firebase configured with your Flutter application.
- Firebase Core configured.
- Cloud Storage enabled in the Firebase project.
Firebase's current Flutter setup uses the FlutterFire CLI to configure the Firebase project and generate firebase_options.dart.
6. Configure Firebase with Flutter
If Firebase is not already configured in your project, install the Firebase CLI and FlutterFire CLI.
firebase login
dart pub global activate flutterfire_cli
From the Flutter project directory, configure Firebase:
flutterfire configure
This generates or updates the Firebase configuration used by the Flutter application.
7. Add Firebase Core
flutter pub add firebase_core
Initialize Firebase in main.dart:
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
8. Add Firebase Storage Package
Install the FlutterFire Storage plugin:
flutter pub add firebase_storage
Import it into Dart:
import 'package:firebase_storage/firebase_storage.dart';
9. Enable Cloud Storage
Open the Firebase Console and navigate to the Storage section. Create or enable the default Cloud Storage bucket and configure its location and Security Rules.
Current Firebase documentation states that Cloud Storage for Firebase requires projects to use the Blaze pay-as-you-go plan. Check Firebase's current pricing and plan requirements before configuring production storage.
10. Access Firebase Storage
The main entry point for Firebase Storage in Flutter is FirebaseStorage.instance.
final storage = FirebaseStorage.instance;
You can also create a reference to the root of the bucket:
final storageRef = FirebaseStorage.instance.ref();
11. What is a Storage Reference?
A Reference acts as a pointer to a location or file inside the Firebase Storage bucket.
final storageRef = FirebaseStorage.instance.ref();
final imagesRef = storageRef.child("images");
final profileRef = storageRef.child("images/profile.jpg");
Here:
storageRef points to the storage root.
imagesRef points to the images path.
profileRef points to the images/profile.jpg file.
12. Understanding Storage Paths
Firebase Storage uses paths to organize files.
images/profile.jpg
images/products/product1.jpg
documents/resume.pdf
videos/tutorial.mp4
audio/song.mp3
A well-organized storage structure makes files easier to manage and secure.
13. Recommended Storage Structure
users/
userId/
profile.jpg
documents/
resume.pdf
products/
productId/
image.jpg
gallery/
image1.jpg
image2.jpg
posts/
postId/
cover.jpg
videos/
videoId/
video.mp4
14. Uploading a File
To upload a file, create a Storage reference and use an upload method such as putFile(), putData(), or putString().
Example Using putFile()
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
Future uploadFile(File file) async {
final storageRef = FirebaseStorage.instance
.ref()
.child("images/profile.jpg");
await storageRef.putFile(file);
}
15. Uploading an Image with a Dynamic File Name
In real applications, file names should usually be generated dynamically instead of using the same name for every upload.
Future uploadImage(File imageFile, String userId) async {
final fileName = DateTime.now().millisecondsSinceEpoch.toString();
final ref = FirebaseStorage.instance
.ref()
.child("users/$userId/profile_$fileName.jpg");
await ref.putFile(imageFile);
}
16. Uploading with Metadata
You can provide metadata such as the content type while uploading a file.
final metadata = SettableMetadata(
contentType: 'image/jpeg',
);
final ref = FirebaseStorage.instance
.ref()
.child('images/profile.jpg');
await ref.putFile(
imageFile,
metadata,
);
17. Why Content Type Matters
The content type identifies the type of file being stored.
| File |
Content Type |
| JPEG image |
image/jpeg |
| PNG image |
image/png |
| PDF |
application/pdf |
| MP4 video |
video/mp4 |
| MP3 audio |
audio/mpeg |
18. Upload Progress
Firebase Storage upload tasks can be monitored to display upload progress to users.
final ref = FirebaseStorage.instance
.ref()
.child('images/profile.jpg');
final uploadTask = ref.putFile(imageFile);
uploadTask.snapshotEvents.listen((TaskSnapshot snapshot) {
final progress = snapshot.bytesTransferred / snapshot.totalBytes;
print('Upload progress: ${(progress * 100).toStringAsFixed(0)}%');
});
19. Upload Task States
A Storage upload task can report different states.
TaskState.running - Upload is in progress.
TaskState.paused - Upload is paused.
TaskState.success - Upload completed successfully.
TaskState.canceled - Upload was canceled.
TaskState.error - Upload failed.
20. Complete Upload Function
Future uploadImage(File imageFile, String userId) async {
final fileName = DateTime.now().millisecondsSinceEpoch.toString();
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/images/$fileName.jpg');
final metadata = SettableMetadata(
contentType: 'image/jpeg',
);
await ref.putFile(imageFile, metadata);
final downloadUrl = await ref.getDownloadURL();
return downloadUrl;
}
This function uploads an image and returns its download URL.
21. Getting a Download URL
After uploading a file, you can obtain a URL using getDownloadURL().
final ref = FirebaseStorage.instance
.ref()
.child('images/profile.jpg');
final url = await ref.getDownloadURL();
print(url);
The URL can be stored in Firestore or used directly by the Flutter application.
22. Store File URL in Firestore
A common architecture is to store the actual file in Firebase Storage and store its URL and related information in Firestore.
final downloadUrl = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(userId)
.set({
'profileImage': downloadUrl,
'updatedAt': FieldValue.serverTimestamp(),
}, SetOptions(merge: true));
23. Display an Image from Firebase Storage
Once you have a download URL, you can display the image using Image.network().
Image.network(
downloadUrl,
width: 120,
height: 120,
fit: BoxFit.cover,
)
24. Complete Profile Image Example
Future uploadProfileImage(
File imageFile,
String userId,
) async {
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/profile.jpg');
await ref.putFile(
imageFile,
SettableMetadata(contentType: 'image/jpeg'),
);
return await ref.getDownloadURL();
}
25. Downloading Files
Firebase Storage provides different ways to retrieve file data. In many Flutter applications, obtaining a download URL is convenient when the file needs to be displayed or handled by another component.
final ref = FirebaseStorage.instance
.ref()
.child('documents/resume.pdf');
final url = await ref.getDownloadURL();
print(url);
26. Download File Data
You can also retrieve the file's bytes using getData().
final ref = FirebaseStorage.instance
.ref()
.child('images/photo.jpg');
final data = await ref.getData();
if (data != null) {
print('Downloaded ${data.length} bytes');
}
27. Getting File Metadata
Firebase Storage provides metadata about stored files.
final ref = FirebaseStorage.instance
.ref()
.child('images/photo.jpg');
final metadata = await ref.getMetadata();
print(metadata.name);
print(metadata.size);
print(metadata.contentType);
print(metadata.timeCreated);
28. Important File Metadata
| Property |
Description |
| name |
File name |
| size |
File size |
| contentType |
MIME type of the file |
| timeCreated |
Time when the file was created |
| updated |
Last update time |
| fullPath |
Complete path of the file |
| bucket |
Storage bucket containing the file |
| customMetadata |
Application-specific metadata |
29. Updating File Metadata
Metadata can be updated after a file has been uploaded.
final ref = FirebaseStorage.instance
.ref()
.child('images/photo.jpg');
final updatedMetadata = await ref.updateMetadata(
SettableMetadata(
contentType: 'image/jpeg',
customMetadata: {
'category': 'profile',
},
),
);
print(updatedMetadata.contentType);
30. Deleting a File
To delete a file, create a reference and call delete().
final ref = FirebaseStorage.instance
.ref()
.child('images/profile.jpg');
await ref.delete();
31. Complete Delete Function
Future deleteImage(String path) async {
final ref = FirebaseStorage.instance.ref().child(path);
await ref.delete();
}
32. Handling Storage Exceptions
Storage operations can fail because of missing files, network problems, permission restrictions, invalid paths, or other conditions.
try {
await ref.putFile(imageFile);
print('Upload successful');
} on FirebaseException catch (e) {
print('Storage error: ${e.code}');
print(e.message);
} catch (e) {
print('Unexpected error: $e');
}
33. Common Firebase Storage Errors
| Error |
Meaning |
| object-not-found |
The requested file does not exist. |
| unauthorized |
The current user does not have permission. |
| canceled |
The operation was canceled. |
| unknown |
An unexpected error occurred. |
| retry-limit-exceeded |
The operation exceeded the retry limit. |
| invalid-checksum |
The uploaded data did not pass integrity validation. |
34. Firebase Storage Security Rules
Security Rules control who can read and write files in Cloud Storage. Firebase Storage is restricted by default, and authenticated access is commonly used for application data.
A basic rule can allow authenticated users to access storage:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
This means only authenticated users can read or write the files covered by the rule.
35. User-Specific Storage Rules
For applications where each user should access only their own files, organize files using the user's Firebase Authentication UID.
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /users/{userId}/{allPaths=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}
This structure allows the application to associate storage paths with authenticated users.
36. Authentication and Firebase Storage
Firebase Authentication and Storage can work together to control access.
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
print(user.uid);
}
The user's UID can then be used as part of the Storage path:
final path = 'users/${user.uid}/profile.jpg';
37. Selecting an Image in Flutter
A common Flutter application uses an image picker package to select an image from the device before uploading it to Firebase Storage.
import 'dart:io';
import 'package:image_picker/image_picker.dart';
Future pickImage() async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
if (pickedFile == null) {
return null;
}
return File(pickedFile.path);
}
38. Image Picker and Firebase Storage Flow
- User taps the upload button.
- Flutter opens the gallery or camera.
- User selects an image.
- The application receives the local file.
- A Firebase Storage reference is created.
- The file is uploaded.
- The application obtains the download URL.
- The URL can be saved in Firestore.
- The image can be displayed in the application.
39. Complete Image Upload Flow
Future selectAndUploadImage(String userId) async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
if (pickedFile == null) {
return;
}
final file = File(pickedFile.path);
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/profile.jpg');
await ref.putFile(
file,
SettableMetadata(contentType: 'image/jpeg'),
);
final url = await ref.getDownloadURL();
print('Image URL: $url');
}
40. Uploading Documents
Firebase Storage can also store documents such as PDF files.
Future uploadPdf(File pdfFile, String userId) async {
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/documents/resume.pdf');
await ref.putFile(
pdfFile,
SettableMetadata(
contentType: 'application/pdf',
),
);
return await ref.getDownloadURL();
}
41. Uploading Videos
Future uploadVideo(File videoFile, String videoId) async {
final ref = FirebaseStorage.instance
.ref()
.child('videos/$videoId/video.mp4');
await ref.putFile(
videoFile,
SettableMetadata(
contentType: 'video/mp4',
),
);
return await ref.getDownloadURL();
}
42. Uploading Audio
Future uploadAudio(File audioFile, String audioId) async {
final ref = FirebaseStorage.instance
.ref()
.child('audio/$audioId/audio.mp3');
await ref.putFile(
audioFile,
SettableMetadata(
contentType: 'audio/mpeg',
),
);
return await ref.getDownloadURL();
}
43. Firebase Storage with Firestore
For many applications, Firebase Storage and Cloud Firestore are used together.
For example, a product image can be stored in Storage while product information is stored in Firestore.
products/
productId/
name: "Laptop"
price: 65000
imageUrl: "https://..."
createdAt: timestamp
The image itself exists in Storage:
products/productId/product.jpg
44. Product Image Upload Example
Future uploadProductImage(
File imageFile,
String productId,
) async {
final ref = FirebaseStorage.instance
.ref()
.child('products/$productId/product.jpg');
await ref.putFile(
imageFile,
SettableMetadata(contentType: 'image/jpeg'),
);
final imageUrl = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('products')
.doc(productId)
.update({
'imageUrl': imageUrl,
});
}
45. Loading State During Upload
Uploading files can take time, so the UI should show a loading indicator.
bool isUploading = false;
Future upload(File file) async {
setState(() {
isUploading = true;
});
try {
final ref = FirebaseStorage.instance
.ref()
.child('images/photo.jpg');
await ref.putFile(file);
} finally {
setState(() {
isUploading = false;
});
}
}
46. Upload Button Example
ElevatedButton(
onPressed: isUploading ? null : uploadSelectedFile,
child: isUploading
? const CircularProgressIndicator()
: const Text('Upload Image'),
)
47. Upload Progress UI
double uploadProgress = 0;
uploadTask.snapshotEvents.listen((snapshot) {
setState(() {
uploadProgress =
snapshot.bytesTransferred / snapshot.totalBytes;
});
});
Display the progress:
LinearProgressIndicator(
value: uploadProgress,
)
48. Pause and Resume Upload
Storage upload tasks can support task control operations such as pausing and resuming.
final uploadTask = ref.putFile(file);
await uploadTask.pause();
await uploadTask.resume();
49. Cancel Upload
final uploadTask = ref.putFile(file);
await uploadTask.cancel();
50. Replacing an Existing File
If a file is uploaded to the same Storage path, the existing object can be replaced by the new upload.
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/profile.jpg');
await ref.putFile(
newImage,
SettableMetadata(contentType: 'image/jpeg'),
);
51. Delete Old Image Before Replacing
When your application uses unique file names, you may need to explicitly delete an old file after a new file is uploaded.
final oldRef = FirebaseStorage.instance
.ref()
.child(oldPath);
await oldRef.delete();
52. File Validation Before Upload
Applications should validate files before uploading them.
- Check whether a file was selected.
- Use appropriate Storage Security Rules.
- Use appropriate content types.
- Handle network and permission errors.
53. Example File Extension Validation
bool isValidImage(String path) {
final extension = path.toLowerCase();
return extension.endsWith('.jpg') ||
extension.endsWith('.jpeg') ||
extension.endsWith('.png');
}
54. File Size Validation
Future isFileSizeValid(File file) async {
final sizeInBytes = await file.length();
final sizeInMB = sizeInBytes / (1024 * 1024);
return sizeInMB <= 5;
}
55. Reusable Firebase Storage Service
For larger applications, Firebase Storage code should be separated from widgets.
class StorageService {
final FirebaseStorage _storage = FirebaseStorage.instance;
Future uploadImage(
File file,
String path,
) async {
final ref = _storage.ref().child(path);
await ref.putFile(
file,
SettableMetadata(contentType: 'image/jpeg'),
);
return await ref.getDownloadURL();
}
Future deleteFile(String path) async {
final ref = _storage.ref().child(path);
await ref.delete();
}
}
56. Using the Storage Service
final storageService = StorageService();
final imageUrl = await storageService.uploadImage(
imageFile,
'users/$userId/profile.jpg',
);
print(imageUrl);
57. Recommended Project Structure
lib/
├── main.dart
├── firebase_options.dart
├── models/
│ └── user_model.dart
├── services/
│ └── storage_service.dart
├── screens/
│ ├── profile_screen.dart
│ └── upload_screen.dart
├── widgets/
│ └── upload_button.dart
└── repositories/
└── file_repository.dart
58. Storage State Management
A file upload screen commonly has the following states:
| State |
Purpose |
| Initial |
No upload has started |
| Picking |
User is selecting a file |
| Uploading |
File is being uploaded |
| Success |
File was uploaded successfully |
| Error |
Upload failed |
59. Example Upload Flow
User selects file
↓
Validate file
↓
Create Storage reference
↓
Start upload
↓
Show progress
↓
Upload successful?
↙ ↘
Yes No
↓ ↓
Get URL Show error
↓
Store URL if required
↓
Display file
60. Firebase Storage and Authentication
Authentication can be used to identify the user who owns a file. A common pattern is to use the authenticated user's UID in the Storage path.
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
return;
}
final userId = user.uid;
final ref = FirebaseStorage.instance
.ref()
.child('users/$userId/profile.jpg');
61. Security Best Practices
- Do not make private application files publicly writable.
- Use Firebase Authentication where appropriate.
- Use Storage Security Rules to control access.
- Validate file types before upload.
- Organize files using predictable paths.
- Use user IDs for user-specific storage.
- Do not trust file names supplied by users.
- Do not store sensitive application information in file metadata unnecessarily.
- Use App Check where appropriate for production applications.
62. Common Mistakes
- Forgetting to add
firebase_storage.
- Not running
flutterfire configure when Firebase configuration needs updating.
- Using an incorrect Storage path.
- Trying to upload to the root without a file path.
- Not handling upload exceptions.
- Not checking whether a file was selected.
- Not showing upload progress.
- Using overly permissive Storage Security Rules.
- Saving the file URL incorrectly in Firestore.
- Not deleting obsolete files when appropriate.
- Uploading very large files without considering bandwidth and storage usage.
63. Firebase Storage and Cloud Firestore Data Model
A practical application can keep the file in Storage and its metadata in Firestore.
Firestore
products/product123
{
"name": "Laptop",
"price": 65000,
"imageUrl": "https://...",
"storagePath": "products/product123/image.jpg"
}
Firebase Storage
products/product123/image.jpg
64. Why Store the Storage Path?
Saving the Storage path in Firestore can make it easier to locate or delete the corresponding file later.
{
"imageUrl": "https://...",
"storagePath": "products/product123/image.jpg"
}
65. Mini Project: Profile Image Upload
Build a Flutter profile screen with the following features:
- Authenticate the user with Firebase Authentication.
- Select a profile image from the gallery.
- Validate the selected image.
- Upload the image to Firebase Storage.
- Display upload progress.
- Get the download URL.
- Save the URL in Firestore.
- Display the uploaded image.
- Allow the user to replace the image.
- Allow the user to remove the image.
66. Mini Project: Product Image Management
Create a product management application where an administrator can:
- Upload the image to Firebase Storage.
- Store the image URL in Firestore.
- Display products in a GridView.
- Update product information.
67. Firebase Storage CRUD Operations
| Operation |
Flutter Method |
| Create/Upload |
putFile(), putData(), putString() |
| Read/Download |
getDownloadURL(), getData() |
| Metadata |
getMetadata(), updateMetadata() |
| Delete |
delete() |
68. Important Firebase Storage Classes
| Class |
Purpose |
FirebaseStorage |
Access Firebase Storage. |
Reference |
Represents a location in Storage. |
UploadTask |
Represents an upload operation. |
TaskSnapshot |
Provides upload task information and progress. |
FullMetadata |
Represents metadata of a stored file. |
SettableMetadata |
Defines metadata during upload or update. |
69. Firebase Storage Best Practices
- Keep Storage paths organized.
- Use authenticated users for private files.
- Write restrictive Security Rules.
- Validate files before upload.
- Use correct MIME types.
- Show progress for large uploads.
- Handle errors gracefully.
- Keep Storage logic outside UI widgets.
- Store application-level file information in Firestore when needed.
- Clean up unused files.
- Monitor storage usage and billing.
- Use App Check as an additional layer where appropriate.
70. Quick Revision
| Concept |
Key Point |
| Firebase Storage |
Cloud object storage for files. |
| Package |
firebase_storage |
| Main instance |
FirebaseStorage.instance |
| Reference |
Points to a Storage path or file. |
| Upload |
putFile() |
| Download URL |
getDownloadURL() |
| Download bytes |
getData() |
| Metadata |
getMetadata() |
| Update metadata |
updateMetadata() |
| Delete |
delete() |
| Security |
Firebase Storage Security Rules |
| User-specific files |
Use authenticated user's UID in paths |
71. Interview Questions
- What is Firebase Storage?
- Why is Firebase Storage used in Flutter applications?
- How do you add Firebase Storage to a Flutter project?
- What is
FirebaseStorage.instance?
- What is a Storage Reference?
- How do you upload a file using
putFile()?
- How do you get the download URL of a file?
- How do you display a Firebase Storage image in Flutter?
- How do you delete a Firebase Storage file?
- What is file metadata?
- What is
SettableMetadata?
- How can upload progress be displayed?
- What is the purpose of Firebase Storage Security Rules?
- How can Firebase Authentication be used with Storage?
- Why should Storage and Firestore sometimes be used together?
- How can files be organized by user ID?
- How should upload errors be handled?
- Why should file type and size be validated?
- What is the difference between Firebase Storage and Firestore?
- How would you design a profile image upload system?
72. Useful Official Resources
73. JustAcademy Flutter Resources
Learn Flutter development and Firebase integration through the following resources:
74. Summary
Firebase Storage provides Flutter applications with a reliable way to upload, store, retrieve, and delete user-generated files. The firebase_storage package provides APIs such as putFile(), getDownloadURL(), getData(), getMetadata(), updateMetadata(), and delete().
A common production architecture stores actual files in Firebase Storage and related application information such as download URLs, file names, user IDs, and timestamps in Cloud Firestore. Firebase Authentication and Storage Security Rules can then be used to control access to user-specific files.
By combining Flutter, Firebase Storage, Firebase Authentication, and Cloud Firestore, developers can build applications with profile images, product galleries, document uploads, video storage, chat attachments, media management, and other file-based features.