Local Data Storage in Mobile Apps

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 30 of 40 servicesAll 1735 services
Simple
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Simple
from 1 business day to 3 business days
Medium
~3-5 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
from 1 business day to 3 business days
Medium
~2-3 business days
Complex
~3-5 business days
Complex
from 1 week to 3 months
Medium
from 1 business day to 3 business days
Medium
~2-3 business days
Medium
~2-3 business days
Medium
from 1 week to 3 months
Simple
from 1 business day to 3 business days
Complex
from 1 week to 3 months
Medium
from 1 week to 3 months
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1050
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Local Storage in Mobile Applications: Core Data, Room, Realm, Hive, Isar

Application loses data on network loss — and this isn't just a bug, it's a scenario failure. User filled in a form, clicked "Send," got timeout and lost everything. Or worse: data was sent twice due to incorrect retry logic. Properly chosen and configured storage layer solves this problem once and for all.

Database Choice — Not a Matter of Taste

In practice, storage choice is determined by two factors: data type and synchronization requirements, not library popularity.

Room (Android) — wrapper over SQLite with compile-time SQL query verification. If query is invalid, build fails — better than SQLiteException at runtime. Room integrates well with Kotlin Flow and LiveData, making reactive UI updates straightforward. Main complexity is schema migrations. @Database(version = N, exportSchema = true) with migration files in assets/databases/ — mandatory practice, otherwise on app update fallbackToDestructiveMigration() just wipes user data.

Core Data (iOS) — not a database, but object graph management framework on top of SQLite (or XML, or in-memory). NSPersistentContainer with viewContext for main thread reading and newBackgroundContext() for writing — basic pattern. Problems start when developer does save() in viewContext from background thread: EXC_BAD_ACCESS at random moment, reproduces once a week, crash log has little useful info. Must use performAndWait or perform for each context strictly in its own thread.

Realm wins where you need speed working with large object sets and built-in reactivity via Results + observe(). Realm stores objects directly, without ORM mapping, so reading doesn't require deserialization. On Flutter Realm SDK (ex-MongoDB Realm) supports Device Sync — but that's already managed service with separate infrastructure.

Hive and Isar — Flutter-specific solutions. Hive — key-value storage, fast, simple, suitable for settings and caches. Isar — full-featured document-oriented database written in Rust, compiles to native code. For Flutter apps with offline functionality, Isar is now preferred: built-in query builder with type-safe filters, transactions, watchObject/watchQuery for reactivity.

Platform Solution Reactivity Synchronization
Android Room + Flow LiveData/Flow WorkManager
iOS Core Data NSFetchedResultsController CloudKit
Flutter Isar Streams Custom / Realm Sync
Cross-platform Realm RealmResults.observe Device Sync
Flutter (simple) Hive ValueListenable None

Offline Synchronization — this is where real complexity begins

Local storage itself isn't complex. Complexity is in synchronization with server when conflicts exist.

Most common pattern — optimistic updates with rollback. User edits record, UI displays change immediately, background request goes to server. If server returns error — rollback local state. Sounds simple. In practice: if user managed to leave screen and return, and rollback happened 3 seconds later — UX is broken. Need explicit operation queue with state (PENDING, SYNCED, FAILED) in separate table.

On Android, for background sync use WorkManager with Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED). Important not to forget setInputMerger(ArrayCreatingInputMerger::class) when batching tasks — otherwise with multiple simultaneous runs data gets overwritten.

On iOS, analog is BGTaskScheduler with BGProcessingTaskRequest. iOS limitations on background execution time (~30 seconds for refresh tasks) mean synchronization must be incremental: not "sync everything," but "sync next N records, save cursor."

Conflicts in multi-device work are solved with one of three approaches:

  • Last-write-wins by updated_at (simplest, loses data with simultaneous editing)
  • Server-wins (client always accepts server version)
  • Three-way merge (complex, need common ancestor — suitable for documents)

In most B2C applications, last-write-wins with time vector per user is enough, but with collaborative editing, CRDT approach is needed — then look at Automerge or Yjs with mobile bindings.

How to Build Storage Layer

Repository pattern is not optional but mandatory. UserRepository doesn't know where data comes from: Room, Realm, or network. ViewModel calls repository.getUser(id), gets Flow/Stream, displays data. Caching logic is inside repository.

For Flutter, typical architecture: Isar for persistence, Riverpod for state management, ConnectivityPlus for network state, custom SyncService with operation queue. Riverpod AsyncNotifier conveniently covers "show cache, update from network, show new data" logic.

Separate topic — encryption. If application stores medical data, payment cards, or corporate documents, SQLCipher (Android) and NSFileProtection (iOS) are not optional. Realm supports encryption natively via 64-byte key, which must be stored in Keychain/Keystore, not SharedPreferences.

Work Stages

Start with requirements audit: what data, what volume, need synchronization, conflicts possible. At this stage it becomes clear: Core Data or SQLite-based solution, need Realm Sync or REST-polling is enough.

Next — schema design considering migrations. Schema changes in any project — question isn't "will there be migrations," but "how painful will they be." Export schema to JSON, store in repository, write tests for each version migration.

Development proceeds with repository layer unit test coverage: mock network layer, real in-memory database for query testing. Before release — query profiling via Android Profiler (Database Inspector tab) or Core Data debug flags (-com.apple.CoreData.SQLDebug 1).

Timeline for storage layer implementation with basic offline sync — 2 to 6 weeks depending on schema complexity and conflict-resolution requirements.