Realm — мобільна об'єктно-орієнтована NoSQL база даних, розроблена як альтернатива SQLite та Core Data для iOS та Android. Дані зберігаються у власному форматі з прямим доступом до об'єктів у пам'яті, що забезпечує високу швидкість читання та запису. Завдяки реактивним сповіщенням, автоматичній синхронізації через Realm Sync та кросплатформній моделі даних, Realm використовується більш ніж на 1 мільярді пристроїв (дані MongoDB, 2025).
Головне
Realm — це об'єктно-орієнтована база даних, створена спеціально для мобільних додатків. На відміну від SQLite, Realm не використовує SQL та реляційну модель — дані зберігаються як живі об'єкти (Live Objects), доступ до яких здійснюється безпосередньо, без проміжного ORM-шару. Розробник працює зі звичайними об'єктами мови (Swift, Kotlin, Dart), які автоматично зберігаються в БД.
Realm з'явився у 2014 році як стартап Realm Inc., а у 2019 році був придбаний MongoDB Inc. З тих пір Realm розвивається як MongoDB Realm — частина єдиної платформи Atlas Device Sync для мобільної синхронізації даних. Базова локальна БД Realm залишається безкоштовною та відкритою (ліцензія Apache 2.0), а Realm Sync (хмарна синхронізація) поширюється за підпискою.
За даними MongoDB Developer Report (2025), Realm використовується в 15% мобільних додатків як основне локальне сховище. Основні сценарії — додатки з офлайн-режимом, складними об'єктними моделями та потребою в синхронізації між пристроями, де Realm перевершує SQLite за швидкістю розробки та зручністю роботи з об'єктами.
Live Objects — кожен об'єкт Realm пов'язаний з диском через відображення в пам'ять (memory-mapped file). Зміна об'єкта в будь-якому потоці негайно відображається у всіх інших потоках без ручного сповіщення. Інтерфейс UI автоматично перемальовується при зміні даних через Realm-сповіщення. Zero-copy — Realm не копіює дані з БД в об'єкти; об'єкти — це і є дані в пам'яті.
Ядро Realm написано на C++ і використовує B+ Tree для індексації даних. На відміну від SQLite, де кожен рядок — це запис у реляційній таблиці, Realm зберігає об'єкти як вузли в графовій структурі з прямими посиланнями між ними (forward pointers). Зв'язки між об'єктами — це не foreign keys, а прямі покажчики, що усуває необхідність в JOIN-операціях.
Файли Realm (розширення .realm) є memory-mapped — ОС сама керує завантаженням сторінок файлу в пам'ять у міру звернення. Це дозволяє Realm працювати з базами, що перевищують доступну оперативну пам'ять, і забезпечує read latency на рівні нативних структур даних мови (Swift Array або Kotlin List) для даних, що вміщуються в RAM.
Memory-mapped файли — ключова технологія Realm. Замість того щоб копіювати дані з файлу БД в об'єкти мови (як робить SQLite через sqlite3_step + sqlite3_column_*), Realm відображає файл бази прямо в адресний простір процесу. Об'єкти мови — це просто покажчики на дані у відображеній пам'яті. Зміна об'єкта змінює базу на диску без окремого save-виклику.
| Характеристика | Realm (zero-copy) | SQLite (копіювання) |
|---|---|---|
| Читання | Прямий доступ до пам'яті (наносекунди) | Копіювання в об'єкт (мікросекунди) |
| Запис | Негайний запис у memory-mapped file | save() з транзакцією SQL INSERT/UPDATE |
| Зв'язки | Прямі покажчики (forward pointers) | Foreign key + JOIN |
| Споживання пам'яті | Файл + кеш сторінок ОС | Об'єкти + кеш сторінок SQLite |
| Живі об'єкти | Так (автоматичне оновлення) | Ні (потрібен новий fetch) |
Споживання пам'яті Realm вище при активному читанні (весь файл або його велика частина відображена в пам'ять), але нижче при операціях запису, оскільки не потрібне виділення пам'яті під копії об'єктів. Для баз розміром до 1 ГБ на мобільних пристроях memory-mapped підхід дає кращу загальну продуктивність, ніж SQLite з його проміжним копіюванням.
SQLite — реляційна СУБД з SQL та ACID-транзакціями. Realm — об'єктна NoSQL БД з memory-mapped доступом. Core Data — ORM-шар Apple поверх SQLite. Кожен із трьох підходів має свою область застосування та сильні сторони. Realm виграє у швидкості прямого доступу до об'єктів та реактивності, SQLite — в універсальності та зрілості, Core Data — в інтеграції з Apple-екосистемою.
Продуктивність Realm на операціях читання на 10-50% вища за SQLite завдяки zero-copy доступу. На операціях запису Realm також швидший за рахунок відсутності SQL-синтаксичного аналізу та прямого змінення memory-mapped сторінок. Однак Realm може споживати більше оперативної пам'яті при роботі з великими базами (>500 МБ), оскільки файл повністю відображається в адресний простір.
| Критерій | Realm | SQLite | Core Data |
|---|---|---|---|
| Тип | NoSQL об'єктна БД | Реляційна СУБД (SQL) | ORM поверх SQLite |
| Швидкість читання | Висока (zero-copy) | Середня | Середня (ORM overhead) |
| Реактивність | Live Objects (вбудовано) | Потрібна обгортка (Room/GRDB) | NSFetchedResultsController |
| Синхронізація | Realm Sync (MongoDB Atlas) | Потрібна кастомна реалізація | NSPersistentCloudKitContainer |
| Платформи | iOS, Android, Flutter, RN, Node.js | iOS, Android, Web, Desktop | Тільки iOS/macOS |
| Розмір бібліотеки | ~4 МБ | ~600 КБ | Вбудовано в SDK |
Вибір між Realm та SQLite часто зводиться до пріоритетів: швидкість розробки та реактивність (Realm) проти контролю та універсальності (SQLite). Realm особливо хороший для MVP та прототипів, де модель даних змінюється часто і важливо швидко отримувати живі оновлення UI. SQLite/Room кращий для зрілих продуктів з великими обсягами даних та складними аналітичними запитами.
Realm Kotlin SDK — офіційна бібліотека для Android, написана на Kotlin (не обгортка над Java SDK). Модель даних визначається через класи, успадковані від RealmObject, з анотацією @PrimaryKey для унікального ідентифікатора. Realm Kotlin підтримує Kotlin Coroutines, Flow та KSP (Kotlin Symbol Processing) для compile-time генерації коду.
RealmQuery надає type-safe API для фільтрації без SQL. Запити будуються ланцюжком методів: query → filter → sort → find. Результат може бути повернутий як список (із завантаженням у пам'ять) або як Flow (реактивний потік, що оновлюється при зміні даних). Realm Kotlin також підтримує вкладені об'єкти та списки (RealmList).
Модель даних Realm визначається як data class, що реалізує інтерфейс RealmObject. Поле _id позначено @PrimaryKey для унікальної ідентифікації. Зв'язок «один-до-багатьох» реалізується через RealmList — список інших RealmObject-ів. Всі операції запису (create, update, delete) виконуються всередині write-блоку транзакції.
class Project : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var name: String = ""
var tasks: RealmList<Task> = realmListOf()
}
class Task : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId().generate()
var title: String = ""
var isComplete: Boolean = false
}
val config = Realm.Configuration.Builder(
schema = setOf(Project::class, Task::class)
).build()
val realm = Realm.open(config)
realm.write { transactionRealm ->
val project = copyToRealm(Project().apply {
name = "Mobile App"
})
project.tasks.add(copyToRealm(Task().apply {
title = "Design UI"
}))
}
val projects: Flow<RealmResults<Project>> =
realm.query<Project>()
.sort(Project::name, Sort.ASCENDING)
.asFlow()
Flow-повертаємий запит автоматично емітує нові результати при будь-якій зміні даних у Realm: додаванні, оновленні або видаленні Project або Task. Flow-підхід ідеально поєднується з Compose: collectAsState() у ViewModel автоматично перекомпоновує UI при зміні даних без ручного оновлення адаптерів списків або використання LiveData.
Realm Swift SDK надає нативний Swift API з підтримкою async/await, Combine Publishers та Swift Concurrency. Моделі даних визначаються як класи, успадковані від Object, з використанням @Persisted для властивостей. Realm Swift автоматично оновлює об'єкти при змінах, а сповіщення (NotificationToken) дозволяють підписуватися на зміни окремих об'єктів або колекцій.
@ObservedRealmObject та @ObservedResults — Property Wrappers для SwiftUI, які автоматично перемальовують View при зміні даних Realm. @ObservedResults працює з результатами запиту, @ObservedRealmObject — з конкретним об'єктом. Обидва властивості скасовують підписку при деініціалізації View.
SwiftUI-інтеграція Realm — одна з сильних сторін SDK. Property Wrapper @ObservedResults пов'язує запит Realm з відображенням у SwiftUI. При зміні будь-якого завдання SwiftUI автоматично перекомпоновує список. realm.writeAsync виконує транзакції на фоновому потоці без блокування UI.
import RealmSwift
class TaskItem: Object, Identifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var title: String = ""
@Persisted var isDone: Bool = false
@Persisted var priority: Int = 0
}
struct TaskListView: View {
@ObservedResults(TaskItem.self,
sortDescriptor: SortDescriptor(["priority"]))
var tasks
var body: some View {
List {
ForEach(tasks) { task in
TaskRow(task: task)
}
}
Button("Add Task") {
let realm = try! Realm()
try! realm.write {
realm.add(TaskItem(value: ["title": "New task"]))
}
}
}
}
@ObservedResults автоматично керує життєвим циклом запиту Realm: при створенні View створюється підписка на зміни, при знищенні — скасовується. Property Wrapper приймає необов'язковий предикат (NSPredicate) та сортування. Це усуває необхідність вручну писати fetch-запити, створювати ViewModel та підписуватися на сповіщення Realm.
Офлайн-додатки — Realm ідеально підходить для сценаріїв, де дані повинні бути доступні без інтернету. Вбудована синхронізація (Realm Sync з MongoDB Atlas) автоматично вирішує конфлікти при підключенні до мережі. Додаток продовжує працювати з локальними даними, а фонова синхронізація оновлює їх при появі з'єднання.
Реактивні інтерфейси — Live Objects та Flow/Combine сповіщення роблять Realm зручним вибором для додатків з часто оновлюваними даними: чати, стрічки завдань, спільні документи. UI автоматично оновлюється при додаванні, зміні або видаленні даних без ручного виклику reloadData або invalidate.
Кросплатформні проекти — Realm підтримує Kotlin Multiplatform (KMP), Flutter, React Native та Xamarin. Модель даних визначається один раз і використовується на всіх платформах. Це скорочує дублювання коду та гарантує консистентність схеми даних між iOS та Android додатками із загальною бізнес-логікою.
Realm Sync — хмарний сервіс, вбудований у MongoDB Atlas. Додаток автоматично синхронізує дані між пристроями користувача та сервером. Конфлікти вирішуються за стратегією «last write wins» або через кастомні Conflict Resolution Functions на сервері. Realm Sync підтримує часткову синхронізацію (subset of data) для зменшення трафіку.
class SyncRepository {
private val app = App(
AppConfiguration(
appId = "my-realm-app-id"
)
)
suspend fun syncData() {
val user = app.login(Credentials.anonymous())
val config = SyncConfiguration.Builder(
user, setOf(Project::class)
).build()
val syncedRealm = Realm.open(config)
// Автоматична синхронізація активна
}
}
SyncConfiguration налаштовує підключення до MongoDB Atlas та визначає набір синхронізованих моделей. Після аутентифікації користувача Realm автоматично завантажує дані з хмари та об'єднує їх з локальними змінами. Синхронізація працює у фоновому потоці та не потребує ручного виклику — достатньо створити екземпляр Realm з SyncConfiguration.
Часті запитання
Так, локальна Realm БД повністю безкоштовна (ліцензія Apache 2.0). Realm Sync (хмарна синхронізація) через MongoDB Atlas — платний сервіс, що входить у підписку Atlas Device Sync. Для безкоштовного рівня Atlas доступні перші 500 МБ даних та 1 млн операцій на місяць.
Так, міграція можлива через експорт даних з SQLite в JSON та імпорт у Realm при першому завантаженні додатка. Для великих обсягів використовуйте потокову міграцію: паралельно записуйте дані в обидві БД, поки користувачі не перейдуть на нову версію додатка, потім видаліть SQLite-файл.
Realm Sync за замовчуванням використовує стратегію «last write wins» — останній запис перезаписує попередній. Для складних конфліктів налаштуйте кастомні Conflict Resolution Functions на сервері MongoDB Atlas, які об'єднують зміни з різних пристроїв за бізнес-логікою додатка (наприклад, merge значень замість заміни).
Realm не підтримує SQL-агрегації (SUM, AVG, GROUP BY) на рівні БД. Для аналітичних запитів рекомендується вивантажити дані з Realm у MongoDB Atlas через Realm Sync та виконувати агрегації через MongoDB Aggregation Pipeline. Для простих підрахунків використовуйте realm.query<T>().count().
Realm не шифрує дані за замовчуванням. Для шифрування вкажіть 64-байтовий ключ у конфігурації: Realm.Configuration(encryptionKey: key). Шифрування використовує AES-256 + SHA-2 HMAC і збільшує накладні витрати на операції на 10-20%. Без шифрування файл .realm читається будь-яким процесом з доступом до файлової системи.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також