Home
Dart
OOP
Flutter
Contact

Firebase Integration — Backend for Flutter Apps

Add authentication, real-time databases, file storage, and push notifications to your Flutter apps with Firebase.

Firebase Overview

Firebase is Google's app development platform that provides a comprehensive suite of backend services. For Flutter developers, it eliminates the need to build and maintain a custom backend.

🔧 Firebase Services for Flutter
  • Authentication — Email/password, Google, Apple, phone sign-in
  • Cloud Firestore — Real-time NoSQL database
  • Cloud Storage — File uploads (images, videos, documents)
  • Cloud Messaging (FCM) — Push notifications
  • Analytics — User behavior tracking
  • Crashlytics — Crash reporting

Setup

pubspec.yaml
dependencies:
  firebase_core: ^3.1.0
  firebase_auth: ^5.1.0
  cloud_firestore: ^5.0.0
  firebase_storage: ^12.0.0
  firebase_messaging: ^15.0.0
  firebase_analytics: ^11.0.0
  firebase_crashlytics: ^4.0.0
main.dart
import 'package:flutter/material.dart';
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());
}
💡 CLI Setup Use the FlutterFire CLI for automatic configuration: dart pub global activate flutterfire_cli && flutterfire configure

Authentication

Firebase Auth provides multiple sign-in methods with minimal code.

auth_service.dart
import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final _auth = FirebaseAuth.instance;

  Stream<User?> get authStateChanges => _auth.authStateChanges();

  User? get currentUser => _auth.currentUser;

  Future<UserCredential> register({
    required String email,
    required String password,
  }) async {
    return _auth.createUserWithEmailAndPassword(
      email: email, password: password,
    );
  }

  Future<UserCredential> signIn({
    required String email,
    required String password,
  }) async {
    return _auth.signInWithEmailAndPassword(
      email: email, password: password,
    );
  }

  Future<UserCredential?> signInWithGoogle() async {
    final googleUser = await GoogleSignIn().signIn();
    if (googleUser == null) return null;

    final googleAuth = await googleUser.authentication;
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );

    return _auth.signInWithCredential(credential);
  }

  Future<void> signOut() async {
    await GoogleSignIn().signOut();
    await _auth.signOut();
  }
}

Auth Gate Widget

auth_gate.dart
class AuthGate extends StreamBuilder<User?> {
  AuthGate({super.key})
      : super(
          stream: AuthService().authStateChanges,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const SplashScreen();
            }
            if (snapshot.hasData) {
              return const HomeScreen();
            }
            return const LoginScreen();
          },
        );
}

Cloud Firestore

Firestore is a real-time NoSQL database with offline support built into the Flutter SDK.

Data Model

projects (collection)
  └── projectId (document)
      ├── title: "My App"
      ├── createdAt: Timestamp
      └── members (subcollection)
          └── memberId (document)
              ├── role: "admin"
              └── joinedAt: Timestamp

CRUD Operations

firestore_service.dart
import 'package:cloud_firestore/cloud_firestore.dart';

class FirestoreService {
  final _db = FirebaseFirestore.instance;

  Future<void> createProject(Project project) async {
    await _db.collection('projects').add(project.toMap());
  }

  Future<Project?> getProject(String id) async {
    final doc = await _db.collection('projects').doc(id).get();
    if (!doc.exists) return null;
    return Project.fromMap(doc.data()!);
  }

  Stream<List<Project>> watchProjects() {
    return _db.collection('projects')
        .orderBy('createdAt', descending: true)
        .snapshots()
        .map((snapshot) => snapshot.docs
            .map((doc) => Project.fromMap(doc.data()))
            .toList());
  }

  Future<void> updateProject(String id, Map<String, dynamic> data) async {
    await _db.collection('projects').doc(id).update(data);
  }

  Future<void> deleteProject(String id) async {
    await _db.collection('projects').doc(id).delete();
  }

  Future<List<Project>> searchProjects({
    required String query,
    int limit = 20,
  }) async {
    final snapshot = await _db.collection('projects')
        .where('title', isGreaterThanOrEqualTo: query)
        .where('title', isLessThanOrEqualTo: '$query\uf8ff')
        .limit(limit).get();

    return snapshot.docs
        .map((doc) => Project.fromMap(doc.data()))
        .toList();
  }
}
⚠️ Firestore Pricing Firestore charges per read, write, and delete operation. Use .snapshots() for real-time data and .get() for one-time reads. Minimize unnecessary reads by using efficient queries and pagination.

Cloud Storage

Firebase Cloud Storage is designed for user-generated content like images, videos, and documents.

storage_service.dart
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';

class StorageService {
  final _storage = FirebaseStorage.instance;

  Future<String> uploadFile({
    required File file,
    required String path,
    void function(double progress)? onProgress,
  }) async {
    final ref = _storage.ref().child(path);
    final uploadTask = ref.putFile(file);

    if (onProgress != null) {
      uploadTask.snapshotEvents.listen((event) {
        onProgress(event.bytesTransferred / event.totalBytes);
      });
    }

    await uploadTask;
    return await ref.getDownloadURL();
  }

  Future<void> deleteFile(String path) async {
    await _storage.ref().child(path).delete();
  }
}

Cloud Messaging (FCM)

Firebase Cloud Messaging enables push notifications and data messaging to your users' devices.

notification_service.dart
import 'package:firebase_messaging/firebase_messaging.dart';

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(
  RemoteMessage message,
) async {
  await Firebase.initializeApp();
}

class NotificationService {
  final _messaging = FirebaseMessaging.instance;

  Future<void> initialize() async {
    final settings = await _messaging.requestPermission(
      alert: true, badge: true, sound: true,
    );

    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      final token = await _messaging.getToken();

      FirebaseMessaging.onMessage.listen((message) {
        _showLocalNotification(message);
      });

      FirebaseMessaging.onMessageOpenedApp.listen((message) {
        _handleNotificationTap(message);
      });

      await _messaging.subscribeToTopic('announcements');
    }
  }
}

Analytics & Crashlytics

Custom Events

import 'package:firebase_analytics/firebase_analytics.dart';

final analytics = FirebaseAnalytics.instance;

await analytics.logEvent(
  name: 'tutorial_completed',
  parameters: {
    'tutorial_name': 'flutter_basics',
    'duration_seconds': 300,
  },
);

Crashlytics

import 'package:firebase_crashlytics/firebase_crashlytics.dart';

try {
  // risky operation
} catch (e, stackTrace) {
  await FirebaseCrashlytics.instance.recordError(
    e, stackTrace,
    reason: 'Failed to load user profile',
  );
}

await FirebaseCrashlytics.instance.setCustomKey('user_type', 'premium');

Firestore Security Rules

Protect your data with server-side security rules. Never rely on client-side validation alone.

firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth != null;
      allow write: if request.auth.uid == userId;
    }

    match /projects/{projectId} {
      allow read: if isMember(projectId);
      allow create: if request.auth != null;
      allow update, delete: if isOwner(projectId);
    }

    function isMember(projectId) {
      return get(/databases/$(database)/documents/projects/$(projectId))
        .data.members.hasAny([request.auth.uid]);
    }

    function isOwner(projectId) {
      return get(/databases/$(database)/documents/projects/$(projectId))
        .data.ownerId == request.auth.uid;
    }
  }
}
⚠️ Security Rules are Critical Misconfigured rules can expose all user data. Test your rules with the Firestore Rules Playground before deploying.

Summary

  • Firebase Auth — Quick sign-in with email, Google, Apple, and phone
  • Cloud Firestore — Real-time NoSQL database with offline support
  • Cloud Storage — File uploads with progress tracking
  • FCM — Push notifications and topic messaging
  • Analytics & Crashlytics — Track usage and monitor crashes
  • Security Rules — Server-side data protection
🚀 Next Step Continue to AI Introduction to learn about integrating AI into Flutter apps.
K
Kesavaraja Murugesan
Flutter Developer & Educator

Flutter developer with 3 years of experience building production-grade mobile applications. Passionate about teaching clean architecture patterns and helping developers write maintainable, scalable code.

← CI/CD & Deployment Next: AI Introduction →