developmentSeptember 16, 2026

    Local-First Flutter: How MindLeau Keeps Your Journal on Your Device

    By Ayesha IftikharSenior Software Engineer & Product Engineer
    Local-First Flutter: How MindLeau Keeps Your Journal on Your Device

    Short answer: what is a local-first Flutter app?

    A local-first app writes data to a database on the device first and treats the cloud as optional sync, not the source of truth. In MindLeau, journal entries and mood check-ins are saved to Drift (a typed SQLite library for Flutter), so the app works fully offline and stays private by default. Firebase Auth and Cloud Firestore are used only if the user chooses to create an account and sync.

    MindLeau is a brain-dump journal and mood tracker for iOS and Android. People write things in it that they would not post anywhere. That shaped the architecture more than any feature did: the default had to be that your words stay on your phone.

    Why local-first for a journaling app

    • Privacy by default. If nothing leaves the device unless you ask, there is much less to protect and much less to explain.
    • It works anywhere. Guided sessions and journaling work without Wi-Fi, which is exactly when some people want them.
    • It feels instant. Saving an entry is a local write, not a network round trip.
    • No forced sign-up. Someone can open the app and start writing in seconds.

    The stack

    • Flutter for one codebase across iOS and Android.
    • Drift on SQLite as the on-device source of truth. Drift gives typed tables and queries in Dart, migrations, and reactive streams, so screens update when the data changes.
    • Firebase Auth and Cloud Firestore for optional background sync once a user creates an account.
    • provider with ChangeNotifier and ValueNotifier for state.

    How the data flows

    The rule is simple: the UI only ever reads from the local database.

    1. The user writes an entry. It is saved to Drift immediately.
    2. The screen is listening to a Drift query stream, so it updates on its own.
    3. If the user has an account, a sync layer pushes local changes to Firestore in the background and pulls remote changes back into Drift.
    4. If the user has no account, step 3 never happens and nothing is lost from the experience.

    Keeping the UI unaware of the network is what makes the offline experience reliable. There is no second code path for when the connection drops.

    Why not Riverpod or Bloc?

    Both are good tools. MindLeau did not need them. Most state in the app is "what is in the database right now", and Drift streams already provide that. The remaining UI state is small enough that provider with ChangeNotifier and ValueNotifier stays readable. Adding a heavier state management layer would have cost more in structure than it saved. Choosing the simplest tool that fits is a decision I make on purpose, not by default.

    The trade-offs

    Local-first is not free. The honest costs:

    • Sync is your problem. A cloud-first app gets consistency from the backend. A local-first app has to decide what happens when the same data changes in two places.
    • Schema migrations live on every device. Every database change needs a tested migration, because you cannot fix user data on a server.
    • No account means no backup. Users who never sign in keep their data on one device. The app needs to say that clearly and make syncing an easy, optional step.
    • Deletion has to be real. MindLeau deletes data instantly from Settings, which means deleting locally and, for synced users, remotely.

    When I would choose local-first again

    Local-first is a strong default for journals, notes, health and habit trackers, field tools, and anything used on unreliable connections. It is a poor fit for products that are social or collaborative at their core, where the shared server state is the product.

    You can read the full MindLeau case study, or if you are planning an app and weighing architecture choices like this one, see how I help with technical product consulting.

    Share this article

    You Might Also Like

    User-Centered Development Practices

    User-Centered Development Practices

    User-centered development from planning to deployment: UI/UX design best practices, accessible design practices and agile software development that keep users at the center of every release.

    Read More →
    Scheduling Class Reminders in Flutter Around iOS's 64-Notification Limit

    Scheduling Class Reminders in Flutter Around iOS's 64-Notification Limit

    How ClassPing schedules a whole semester of class reminders offline with flutter_local_notifications: a 60-reminder rolling window under iOS's 64 cap, stable notification IDs, a serial scheduling queue, inexact Android alarms and reboot handling.

    Read More →
    The Hidden Dangers of 'Vibe Coding' with AI

    The Hidden Dangers of 'Vibe Coding' with AI

    Vibe coding—stitching together AI-generated snippets until it 'works'—is the new technical debt. Here's why you need to understand what you ship.

    Read More →