Setting Up Realm Object Database for iOS and Android

When the database grows, the app starts to slow down and users leave. We set up the Realm object database turnkey: we design the schema, migrate data, and accelerate the interface response. You get stable performance at any volume and predictable timelines.

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.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a mobile application for FEEDME
    Development of a mobile application for FEEDME
    971
  • Development of a mobile application for XOOMER
    Development of a mobile application for XOOMER
    869
  • Development of a mobile application for RHL
    Development of a mobile application for RHL
    1289
  • Development of a mobile application for ZIPPY
    Development of a mobile application for ZIPPY
    1143
  • Development of a mobile application for Affhome
    Development of a mobile application for Affhome
    1076
  • Development of a mobile application for the FLAVORS company
    Development of a mobile application for the FLAVORS company
    677

Why a mobile app slows down as data grows

An app that flies at launch starts to slow down noticeably once the local database grows past the first tens of thousands of records.

A contact list or an order feed loads in fits and starts, search responds with a delay, and scrolling stutters — because every query to the mobile app's local storage now goes to disk instead of cache, and runs on the main UI thread.

Then the second problem kicks in — desynchronization. Some data has already made it to the server, some is still stuck in the queue, and after a restart the user sees an outdated picture: an order they already submitted is hanging as a draft again.

When the connection drops in the subway or an elevator, unwritten changes are lost entirely if the storage can't survive a transaction interruption.

Offline data synchronization is a story of its own. When the app comes back online, it tries to merge the accumulated edits in one burst: version conflicts are resolved by "last writer wins," and a heavy pass over the entire table blocks the UI for seconds.

The user sees a frozen screen and closes the app — right at the moment when the write still hasn't been committed.

All three failures share the same root cause: the local storage was designed for a demo volume, not for real growth.

This is where realm database comes to the fore — an object storage where records are read as ordinary objects, queries run on indexes, and changes arrive in the UI reactively, without manually re-reading tables.

Let's break down how this is solved in practice: from the storage schema and indexes to the deferred synchronization queue and conflict resolution rules.

What a properly configured realm database provides

Data schema as the foundation of interface responsiveness

Interface responsiveness is determined not by device power, but by how the application's data schema is designed.

When objects are described by relationships rather than nested copies, list retrieval goes through an indexed field and fits within fractions of a frame — scrolling stays smooth even on large collections.

A flat schema without indexes produces the opposite effect: each screen reassembles the data from scratch, and the interface "sticks" as the database grows.

Synchronization modes and resilience to connection drops

The key parameter is the synchronization mode. Local writes with background upload allow the application to work offline: the user sees up-to-date data from local storage, and changes are sent to the server as soon as the connection is restored.

The queue of changes survives an application restart, so no edit is lost when the network drops in the subway or an elevator. This eliminates an entire class of failures — "data wasn't saved" and "the screen is empty without internet."

What configuration delivers in practice

Option When it fits Limitations
Local database without synchronization Reference data, cache, offline mode No shared data between devices
Local writes + background synchronization Most product applications Version conflict handling required
Direct operation through the server Data always online, small volume Interface depends on connection quality

We work on Realm — an object database delivers list responsiveness many times faster compared to building queries on top of file storage, and the volume of overhead data with a correct schema is reduced threefold.

Measurable result

After configuring the schema and synchronization modes, the time to open heavy screens drops from seconds to fractions of a second, and the share of requests that ended in an error under an unstable network falls to single-digit percentages.

A separate class of failures related to desynchronization also disappears: the user no longer sees stale data after returning to the application.

How we set up storage: stages of engineering work

Setting up local storage starts not with code, but with an audit: we look at what entities already live on the device, how they are related, where records are duplicated, and which queries run on the main thread.

It often turns out that some data doesn't need to be stored offline at all, while some, on the contrary, is lost when the app is updated. This determines the schema, indexes, and the strategy for syncing with the server.

  1. Storage audit. We analyze the current schema, data volume, read and write frequency, and behavior on logout and reinstall. We identify bottlenecks: heavy queries, missing indexes, write locks.
  2. Data schema design. We define entities, relationships, and field types for real screen scenarios, not "for the future." We build in schema versioning so that the next app update doesn't break user data.
  3. Configuration and migrations setup. We describe the rules for transitioning between schema versions, the order of adding and removing fields, and behavior when rolling back to a previous build. App data migration happens without losing user records.
  4. Query optimization. We move heavy queries off the main thread, add indexes for specific filters and sorts, and check behavior on low-end devices and when storage is full.
  5. Testing on real data. We run through update scenarios, interrupted writes, low space, and concurrent access. We look at what happens when the local and server versions of a record conflict.
  6. Documentation handover. We deliver the schema, migration rules, index descriptions, and instructions for adding new fields — so the client's team can evolve the storage without us.

We describe the schema and migration rules so they can be read without diving into code: a table of entities, relationships, versions, and the order of changes.

This eliminates the typical problem where, six months later, no one remembers why a field is named that way and what to do with it in the next release.

How does a local database differ from cloud synchronization?

The Realm database solves two different problems that are often confused: storing data on the device and synchronizing it between devices and the server. Local storage is a file on the phone's disk that the app accesses directly, without a network.

Cloud synchronization is a layer on top that tracks changes to objects and transfers them between devices via the server, resolving conflicts according to defined rules. It's not an "either-or": synchronization works on top of local storage, not instead of it.

The difference shows up the moment the network drops. In local mode, the app keeps reading from and writing to the database at the same speed — requests go to the file, not the server, so the interface doesn't freeze or show endless loading indicators.

With synchronization and no well-designed offline mode, some of the app's operations queue up and wait for connectivity to return, and conflicting edits have to be resolved after the fact.

That's exactly why choosing a storage mode starts not with the question "do we need synchronization" but with the question "what must work without a network."

There's a second cost as well — the complexity of the data model. A local schema lives by the rules of a single device: migrations are applied when the app updates, the schema version grows linearly, and rollback is predictable.

Synchronization adds dimensions — multiple devices edit the same object, some changes arrive with a delay, and server-side access logic must match the client-side logic.

The more entities involved in the exchange, the more expensive a mistake in the conflict resolution rules becomes: the user notices data discrepancies between devices before you get a signal.

The practical rule is simple. If the data belongs to one device and one user — notes, a catalog cache, drafts, settings — local storage is enough, and it delivers minimal response time.

If the same dataset must be visible on multiple devices or pulled onto a new phone after sign-in — you need synchronization, but with an explicitly described offline mode for the app: what gets written locally, what goes into the queue, what conflicts and how.

A mixed approach also works: reference data and user content are synchronized, while heavy local data stays on the device.

The mistake we see most often is enabling synchronization "just in case" and ending up with growing traffic, interface delays, and discrepancies that can't be reproduced. The opposite mistake is keeping everything local where the user expects their data on a second device.

We analyze usage scenarios, determine which entities must survive a device change, and only then choose the storage mode. Describe your task — we'll come back with an estimate and a plan.

Case study: we sped up the app threefold on a growing dataset

The client came with a complaint: the app "freezes" when opening the orders list.

On a test set of a couple hundred records everything was fast, but in production the managers had accumulated several tens of thousands of objects — and the screen took 2.5–3 seconds to open, scrolling stuttered, and searching through history had a noticeable delay.

Measurements showed that most of the time went not into rendering but into reading from storage — queries ran on the main thread, the schema was flat, and synchronization pulled the entire set of objects on every launch.

What we changed

We reworked the schema: we split related entities into separate tables, added indexed fields for filtering and sorting, and removed duplicate nested collections.

Heavy reads were moved to background queues, and the result was delivered to the UI through change observation — the list updates itself, without manual refetches.

Synchronization was switched from a full dump to incremental: the client requests only changed records by timestamp, and conflicts are resolved by the "last write wins" rule with a log for reviewing disputed cases.

In parallel, we set up a cleanup policy: stale records older than a given period are deleted by a background task, and the storage volume stopped growing indefinitely.

Metrics before and after

Metric Before After
List opening 2.5–3 s 0.8–0.9 s
Scrolling stuttering stable frames
Full synchronization at startup entire set only changes
Storage growth linear bounded by cleanup policy

We also measured cold start separately: the time to a ready screen was cut by almost three times, and memory consumption on low-end devices dropped by roughly a third — the app stopped being killed by the system in the background.

Result of implementation

Speed increased threefold on real data volumes, not on a demo set. Out-of-memory crashes are gone, and complaints about "lag" stopped. The schema and synchronization rules were documented so the client's team could evolve them without us.

We worked with Realm — an object database that stores data directly on the device and does not require a separate server.

Concerns before implementation: compatibility, migration, rollback

What happens to the data schema when the application is updated — will user data be lost?

The schema is versioned, and transitions between versions are described by explicit rules: which fields were added, renamed, or removed, and how values are carried over.

On startup, the application applies the transition once, within a transaction — if it fails, the database remains in its previous state rather than in a half-assembled one.

Before the first launch of a new version on a device, a backup of the storage file is made, so rolling back to a previous version of the application does not leave the user without data.

What if you need to return to a previous version? Rolling back changes is not just reverting the build, but also reversing the schema transition. We describe it in advance for each release so that reverting does not turn into manual editing of data on devices.

How is access to the storage delineated? Access to the storage is described by roles: who reads, who writes, who changes the schema. This is recorded in the database documentation rather than left in the developer's head.

What if some users have an old version of the application? Several schema versions are supported in parallel while a gradual update is underway — synchronization does not break for those who have not yet updated.

After handover, the client receives:

  • a description of the data schema with versions and rules for transitions between them;
  • a set of data migration rules for each release, with validation on real volumes;
  • a procedure for rolling back changes — both the schema and the application;
  • a matrix of access to the storage by roles;
  • database documentation: structure, relationships, constraints, backup procedure;
  • a set of automated checks that are run before each update;
  • an instruction for the support team: how to read the state of the database and what to do in case of failure.

Describe your task — we will come back with an estimate and a plan: we will show how the schema will fit onto the current data and what steps will be required during the first update.