Skip to content

Local Database Options

Local data storage in mobile applications is critical for performance, offline functionality, and user experience. This section examines all local persistence options in detail, from SQL-based solutions to NoSQL alternatives, from key-value stores to object databases.

SQL-Based Solutions

SQLite/Room (Android)

Room is a modern database abstraction that provides an ORM layer over SQLite on Android, offering compile-time verification and type safety.

Core Components

@Entity Annotations

  • Primary key definitions and auto-increment features
  • Foreign key relationships and referential integrity
  • Index definitions and composite indexes
  • Custom table names and column configurations

@Dao (Data Access Object)

  • SQL queries and parametric queries
  • @Insert, @Update, @Delete annotations
  • Custom SQL queries with @Query
  • Reactive programming with LiveData/Flow

@Database Configuration

  • Room database versioning
  • Entity lists and type converters
  • Migration strategies
  • In-memory and file-based database options

Advanced Features

Migration Strategies

kotlin
// Room migration example
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL")
    }
}

@Database(
    entities = [User::class],
    version = 2,
    exportSchema = false
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
    
    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null
        
        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                )
                .addMigrations(MIGRATION_1_2)
                .build()
                INSTANCE = instance
                instance
            }
        }
    }
}

Reactive Queries

  • UI reactive updates with LiveData
  • Asynchronous data streams with Kotlin Flow
  • RxJava integration
  • Coroutines support

Performance Optimizations

  • WAL (Write-Ahead Logging) mode
  • Prepared statements and statement caching
  • Batch operations and bulk insert/update
  • Connection pooling
  • Index optimization

SQLite Cross-Platform Implementations

Flutter - sqflite & drift

sqflite: Flutter's native SQLite plugin

  • Native SQLite access via platform channels
  • Transaction support and batch operations
  • Database versioning and migration
  • Custom SQL and raw query support
dart
// sqflite example
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper._internal();
  static Database? _database;

  DatabaseHelper._internal();

  factory DatabaseHelper() => _instance;

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    String path = join(await getDatabasesPath(), 'app_database.db');
    return await openDatabase(
      path,
      version: 1,
      onCreate: _onCreate,
      onUpgrade: _onUpgrade,
    );
  }

  Future<void> _onCreate(Database db, int version) async {
    await db.execute('''
      CREATE TABLE users(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        created_at INTEGER NOT NULL
      )
    ''');
  }

  Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
    if (oldVersion < 2) {
      await db.execute('ALTER TABLE users ADD COLUMN age INTEGER DEFAULT 0');
    }
  }
}

drift (formerly moor): Type-safe SQL generation

  • SQL schema definitions with Dart
  • Compile-time SQL validation
  • Boilerplate elimination with code generation
  • Stream-based reactive queries

React Native Solutions

react-native-sqlite-storage

  • Unified API for iOS and Android
  • Promise-based and callback-based operations
  • WAL mode support
  • Encryption capabilities

WatermelonDB

  • Reactive database with Observable patterns
  • Lazy loading and performance optimization
  • Multi-threaded architecture
  • Sync protocol with backend integration

Xamarin - SQLite.NET

  • Native SQLite binding with C#
  • ORM capabilities and LINQ queries
  • Encryption support (SQLCipher)
  • Cross-platform code sharing

NoSQL Solutions

Core Data (iOS)

Core Data is Apple's object graph management and persistence framework, providing comprehensive data modeling solutions for iOS and macOS applications.

Core Components

NSManagedObjectModel

  • Entity definitions and relationships
  • Attribute types and validation rules
  • Fetch request templates
  • Configuration and versioning

NSPersistentStoreCoordinator

  • Store type management (SQLite, Binary, In-Memory)
  • Migration coordination
  • Store metadata handling
  • Multi-store configurations

NSManagedObjectContext

  • Object lifecycle management
  • Change tracking and validation
  • Concurrent queue types (main, private)
  • Parent-child context hierarchies

SwiftData (iOS 17+)

SwiftData is Apple's modern declarative data modeling framework, built on top of Core Data with Swift-native syntax.

Key-Value Stores

Shared Preferences (Android)

Android's key-value storage for primitive data types and small amounts of data.

UserDefaults (iOS)

iOS's property list-based storage for user preferences and simple data.

Cross-Platform Key-Value Solutions

AsyncStorage (React Native)

Asynchronous, persistent key-value storage system for React Native applications.

Shared Preferences (Flutter)

Platform-agnostic key-value storage for Flutter applications.

Hybrid and Cloud-Integrated Solutions

Firebase Local Persistence

Firebase offers local caching and offline support for both Firestore and Realtime Database.

Realm Database

Realm is a modern object database that provides a simple alternative to SQLite and Core Data.

Performance Considerations

Indexing Strategies

  • Primary Key Optimization: Use appropriate data types and auto-increment when possible
  • Composite Indexes: Create indexes for multi-column queries
  • Partial Indexes: Index only relevant rows to reduce storage overhead
  • Covering Indexes: Include all queried columns to avoid table lookups

Query Optimization

  • Prepared Statements: Reuse compiled queries for better performance
  • Batch Operations: Group multiple insert/update operations
  • Lazy Loading: Load related objects only when needed
  • Pagination: Implement cursor-based or offset-based pagination

Memory Management

  • Connection Pooling: Reuse database connections
  • Result Set Streaming: Process large datasets incrementally
  • Cache Management: Implement intelligent caching strategies
  • Background Processing: Perform heavy operations on background threads

Storage Efficiency

  • Data Compression: Use BLOB compression for large objects
  • Normalization: Reduce data redundancy through proper table design
  • Archiving: Move old data to separate tables or files
  • Vacuum Operations: Regularly optimize database file structure

Best Practices

Security Architecture

Testing Strategy

Database Architecture Overview

Performance Optimization Flow

Security

  • Data Encryption: Encrypt sensitive data at rest
  • Access Control: Implement proper data access permissions
  • SQL Injection Prevention: Use parameterized queries
  • Secure Key Management: Store encryption keys securely

Architecture

  • Repository Pattern: Abstract data access logic
  • Dependency Injection: Make database access testable
  • Error Handling: Implement comprehensive error recovery
  • Migration Management: Plan for schema evolution

Testing

  • Unit Testing: Test data access logic in isolation
  • Integration Testing: Test database operations end-to-end
  • Mock Databases: Use in-memory databases for testing
  • Data Validation: Ensure data integrity at all levels

Monitoring

  • Performance Metrics: Track query execution times
  • Error Logging: Log database errors and exceptions
  • Usage Analytics: Monitor data access patterns
  • Capacity Planning: Track storage growth and usage trends

Created by Eren Demir.