← Back to posts Cover image for Migrating Local Databases in Flutter: From Realm to Drift (and Beyond)

Migrating Local Databases in Flutter: From Realm to Drift (and Beyond)

· 3 min read
Weekly Digest

The Flutter news you actually need

No spam, ever. Unsubscribe in one click.

Chris
By Chris

So your Flutter app’s local database has become a liability. Maybe it’s crashing randomly, or the package you chose has stopped receiving updates. You’re not alone—many of us have been there. The initial prototype often uses the most convenient database, but as your app grows and you need stability, a migration becomes inevitable.

A common path is moving from an unmaintained or unstable NoSQL solution like Realm to a robust, SQLite-based library such as Drift. This migration isn’t just about swapping packages; it’s a strategic move towards long-term data integrity and reliability.

Let’s break down how to approach this migration methodically.

Step 1: Audit and Understand Your Current Data

Before writing a single line of new code, you need a complete map of your existing data. What objects are stored? What are their relationships? Export a sample of your Realm database and document the schema.

For example, if you had a Session object in Realm:

// Old Realm Model (Conceptual)
class OldSession {
  @PrimaryKey()
  int? id;
  String mantraName;
  int count;
  DateTime date;
}

Step 2: Design the New Drift Schema

With Drift, you define your schema using Dart (or SQL). Design your new tables, keeping future needs in mind.

Here’s how you might define the equivalent sessions table:

import 'package:drift/drift.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'dart:io';

part 'database.g.dart';

class Sessions extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get mantraName => text()();
  IntColumn get count => integer()();
  DateTimeColumn get date => dateTime()();
}

@DriftDatabase(tables: [Sessions])
class AppDatabase extends _$AppDatabase {
  AppDatabase() : super(_openConnection());
  @override
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(p.join(dbFolder.path, 'app_db.sqlite'));
    return NativeDatabase(file);
  });
}

Step 3: The Migration Script: A Critical Phase

This is the heart of the process. You must write a one-time script that reads all data from the old Realm database and writes it into the new Drift database. Do this during your app’s first launch after the update.

Create a dedicated migration service:

class DatabaseMigrator {
  final Realm oldRealmInstance;
  final AppDatabase newDriftDatabase;

  Future<void> migrateAllData() async {
    // 1. Read all old objects
    final oldSessions = oldRealmInstance.all<OldSession>();

    // 2. Transform and insert into new database
    for (final oldSession in oldSessions) {
      await newDriftDatabase.into(newDriftDatabase.sessions).insert(
            SessionsCompanion.insert(
              mantraName: Value(oldSession.mantraName),
              count: Value(oldSession.count),
              date: Value(oldSession.date),
            ),
          );
    }
    // 3. Close the old realm
    oldRealmInstance.close();
  }
}

Crucial: Wrap this in extensive error handling and logging.

Step 4: Update Your App’s Architecture

Your old data layer was tightly coupled to Realm. Now’s the time to abstract it. Implement a repository pattern that uses your new AppDatabase.

abstract class SessionRepository {
  Future<List<Session>> getAllSessions();
  Future<void> addSession(Session session);
}

class DriftSessionRepository implements SessionRepository {
  final AppDatabase db;
  DriftSessionRepository(this.db);

  @override
  Future<List<Session>> getAllSessions() async {
    final rows = await db.select(db.sessions).get();
    return rows.map((row) => Session.fromRow(row)).toList();
  }
  // ... other methods
}

Step 5: Planning for the Cloud

Once you have a stable local SQLite foundation, adding cloud sync becomes a more manageable problem.

Final Advice

  • Test Relentlessly: Create a comprehensive suite of unit and integration tests for your migration script and new data layer.
  • Communicate with Users: For a production app, consider a phased rollout.
  • Embrace the Refactor: This migration is a significant investment. Use it as an opportunity to clean up related technical debt in your data layer.

Migrating your database is a complex, high-stakes task, but moving to a well-maintained, standards-based solution like Drift provides the rock-solid foundation your app needs to grow.

This blog is produced with the assistance of AI by a human editor. Learn more

Related Posts

Cover image for Flutter's Hidden Gem: Building Powerful Linux Desktop Apps with Ease

Flutter's Hidden Gem: Building Powerful Linux Desktop Apps with Ease

Flutter is gaining traction as a robust framework for Linux desktop development, offering a smoother experience compared to traditional toolkits like GTK and Qt. This post will explore why Flutter excels for Linux apps, highlight its advantages, and provide practical insights for developers looking to leverage Flutter for their desktop projects.

Cover image for Simplifying Flutter Desktop Deployment: Signing and Distribution for Windows

Simplifying Flutter Desktop Deployment: Signing and Distribution for Windows

Deploying Flutter desktop apps on Windows can be challenging, especially regarding code signing and preventing Windows from blocking installations. This post will guide developers through the process of signing their Flutter desktop applications, exploring alternatives to the Microsoft Store like creating executable installers, and covering the necessary steps to ensure a smooth user experience.

Cover image for Mastering Flutter Tooling: Streamlining SDK Management and Installation on Windows

Mastering Flutter Tooling: Streamlining SDK Management and Installation on Windows

Developers frequently voice frustrations about Flutter SDK version management and installation processes, particularly on Windows. This post will explore best practices for managing multiple Flutter versions using tools like FVM, discuss integrating Flutter with package managers like Winget for a smoother Windows setup, and offer strategies to ensure a consistent development environment across projects and teams.