Firebase: Your Complete Backend Solution for Flutter
Firebase gives you authentication, a real-time database, file storage, cloud functions, and analytics — all wired together and ready to use from your Flutter app. No server setup, no DevOps. Here's how to actually use each service.
Setup
Install the FlutterFire CLI and initialize:
# Install the CLI globally
dart pub global activate flutterfire_cli
# Initialize Firebase in your Flutter project
flutterfire configure
This generates firebase_options.dart. Then initialize in your app:
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
Authentication
Firebase Auth handles email/password, Google Sign-In, Apple Sign-In, and phone number verification. Here's the practical implementation:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// Current user as a stream — drives your UI reactively
Stream<User?> get authStateChanges => _auth.authStateChanges();
// Email + Password sign up
Future<UserCredential> signUp(String email, String password) async {
return await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
}
// Email + Password sign in
Future<UserCredential> signIn(String email, String password) async {
return await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
}
// Google Sign-In
Future<UserCredential> signInWithGoogle() async {
final googleUser = await GoogleSignIn().signIn();
if (googleUser == null) throw Exception('Google sign-in cancelled');
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
return await _auth.signInWithCredential(credential);
}
Future<void> signOut() => _auth.signOut();
}
Listen to auth state changes in your app to redirect between login and home:
StreamBuilder<User?>(
stream: authService.authStateChanges,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const SplashScreen();
}
return snapshot.hasData ? const HomeScreen() : const LoginScreen();
},
)
Cloud Firestore
Firestore is a NoSQL document database with real-time sync and offline support built in. Data is organized in collections and documents.
Writing Data
class TaskRepository {
final FirebaseFirestore _db = FirebaseFirestore.instance;
Future<void> createTask(Task task) async {
await _db.collection('users')
.doc(task.userId)
.collection('tasks')
.doc(task.id)
.set({
'title': task.title,
'isCompleted': task.isCompleted,
'createdAt': FieldValue.serverTimestamp(),
'priority': task.priority.name,
});
}
Future<void> toggleComplete(String userId, String taskId) async {
final ref = _db.collection('users').doc(userId).collection('tasks').doc(taskId);
final doc = await ref.get();
await ref.update({
'isCompleted': !(doc.data()?['isCompleted'] ?? false),
'updatedAt': FieldValue.serverTimestamp(),
});
}
}
Reading Data in Real-Time
// One-time fetch
Future<List<Task>> getTasks(String userId) async {
final snapshot = await _db
.collection('users')
.doc(userId)
.collection('tasks')
.orderBy('createdAt', descending: true)
.get();
return snapshot.docs.map((doc) => Task.fromFirestore(doc)).toList();
}
// Real-time stream — UI updates automatically when data changes
Stream<List<Task>> watchTasks(String userId) {
return _db
.collection('users')
.doc(userId)
.collection('tasks')
.orderBy('createdAt', descending: true)
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => Task.fromFirestore(doc)).toList(),
);
}
Security Rules
Firestore Security Rules control who can read and write. Without them, your data is wide open:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can only access their own data
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}
Cloud Storage
For user-uploaded files — profile pictures, documents, images:
class StorageService {
final FirebaseStorage _storage = FirebaseStorage.instance;
Future<String> uploadProfileImage(String userId, File file) async {
final ref = _storage.ref('users/$userId/profile.jpg');
// Upload with metadata
await ref.putFile(
file,
SettableMetadata(contentType: 'image/jpeg'),
);
// Get the download URL
return await ref.getDownloadURL();
}
Future<void> deleteFile(String path) async {
await _storage.ref(path).delete();
}
}
Cloud Functions
Server-side logic that runs in response to events. Write in TypeScript, deploy to Google Cloud:
// functions/src/index.ts
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
import { getMessaging } from 'firebase-admin/messaging';
export const onNewTask = onDocumentCreated(
'users/{userId}/tasks/{taskId}',
async (event) => {
const task = event.data?.data();
const userId = event.params.userId;
// Send push notification when a task is created
await getMessaging().sendToTopic(userId, {
notification: {
title: 'New Task',
body: task?.title ?? 'You have a new task',
},
});
}
);
Offline Support
Firestore has offline support enabled by default on mobile. When the user loses connection:
- Writes are queued locally
- Reads come from the local cache
- When connection returns, queued writes sync automatically
You don't write any extra code for this. It just works.
// This works even offline
await _db.collection('tasks').add({
'title': 'Buy groceries',
'isCompleted': false,
});
// Firestore queues the write and syncs when back online
When to Use Firebase
| Use Case | Firebase Service |
|---|---|
| User login/signup | Firebase Auth |
| App data (CRUD) | Cloud Firestore |
| File uploads | Cloud Storage |
| Push notifications | Cloud Messaging |
| Server logic | Cloud Functions |
| Crash tracking | Crashlytics |
| User analytics | Google Analytics |
When NOT to Use Firebase
- Complex relational data: If your data has many join tables and complex relationships, PostgreSQL (via Supabase) is better.
- Full SQL access: Firestore is NoSQL. No JOINs, no aggregations beyond basic counts.
- Self-hosting requirement: Firebase is Google Cloud only.
- Predictable pricing at scale: Firestore charges per read/write. High-traffic apps can get expensive fast.
The Bottom Line
Firebase is the fastest way to go from zero to a production backend. Auth, database, storage, push notifications — it's all there, wired together, with offline support out of the box. Start with Auth + Firestore, add services as you need them.



