Firebase Without the Dependency

Socialmesh works fully offline. No internet, no accounts, no cloud. But Firebase is there if you want it — cloud sync, profiles, the widget marketplace. The trick is making Firebase truly optional, not just theoretically optional.

The Problem

Most Firebase tutorials show eager initialization at app startup:

// The typical approach (DON'T DO THIS)
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();  // blocks startup
  runApp(MyApp());
}

This blocks app startup until Firebase connects. On a slow network, that is seconds of blank screen. With no network, it can timeout entirely. For an app designed for off-grid use, this is unacceptable.

Background Initialization

Firebase initializes in the background with a timeout. The app launches immediately with full functionality. Firebase features activate later if initialization succeeds:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
  // Firebase initializes in the background
  _initFirebaseInBackground();
}

Future<void> _initFirebaseInBackground() async {
  try {
    await Firebase.initializeApp()
        .timeout(const Duration(seconds: 10));
    // Enable cloud features
  } catch (_) {
    // App continues without cloud features
  }
}

Feature Gating

Every Firebase-dependent feature has a local fallback:

FeatureWith FirebaseWithout Firebase
ProfileCloud-syncedLocal-only
Widget marketplaceBrowse and installUse bundled widgets
Node syncCross-deviceDevice-local
Crash reportingCrashlyticsSilent (no data sent)
AnalyticsEvent trackingDisabled

The UI does not show “sign in to enable” prompts or disabled buttons. Features that need Firebase simply do not appear in the UI when Firebase is unavailable. No error states, no degraded UX messaging. The app feels complete either way.

Firestore Collections

When Firebase is available, Firestore stores:

  • users — authentication metadata
  • profiles — public user profiles (display name, avatar, bio)
  • widgets — marketplace widget schemas
  • shopProducts — in-app purchase catalog
  • shared_nodes — cross-device node persistence

All writes are fire-and-forget with offline persistence enabled. Firestore’s local cache means reads work even after the connection drops. The data eventually syncs when connectivity returns.

Key Principle

The app must be indistinguishable from a non-Firebase app when offline. If removing Firebase would require any UI changes, the integration is too tight.