Firebase Realtime Database to chmurowa baza danych NoSQL Google z synchronizacją zmian w czasie rzeczywistym przez stałe połączenie WebSocket. Dane są przechowywane jako pojedyncze drzewo JSON, a każda zmiana dowolnego węzła jest natychmiast dostarczana do wszystkich podłączonych klientów. Według danych Google, 2026, Realtime Database obsługuje do 200 tysięcy jednoczesnych połączeń z jedną instancją. Usługa jest dostępna z darmowym limitem 1 GB pamięci i 10 GB transferu miesięcznie.
Najważniejsze
Firebase Realtime Database to jedna z pierwszych chmurowych baz danych czasu rzeczywistego, uruchomiona przez Google wraz z Firebase w 2012 roku. Jest to baza NoSQL, w której dane są przechowywane jako pojedyncze drzewo JSON dostępne pod jednym URL. Klienckie SDK (Android, iOS, Web) subskrybują konkretne węzły drzewa przez WebSocket i otrzymują aktualizacje przy każdej zmianie danych — bez pingowania serwera i bez implementacji własnego mechanizmu Push.
Oryginalne Firebase zostało założone w 2011 roku przez Jamesa Tamplina i Andrew Lee, a pierwszym produktem była właśnie Realtime Database. Po przejęciu przez Google w 2014 roku (według TechCrunch — za kwotę od 50 do 100 milionów dolarów) baza została zintegrowana z Google Cloud i uzyskała znacznie wyższą przepustowość. W 2017 roku Google ogłosiło Firestore jako ewolucyjny zamiennik, ale Realtime Database nadal jest aktywnie wspierana i rozwijana. Według danych Google (2026), Realtime Database jest nadal używana w ponad 1,5 miliona aktywnych projektów.
Spark (darmowy) obejmuje: 1 GB pamięci, 10 GB pobranych danych miesięcznie, 100 jednoczesnych połączeń i obsługę bazy danych w jednym regionie. W taryfie Blaze (pay-as-you-go) opłaty są pobierane za dodatkową pamięć (1 $/GB), transfer (0,12 $/GB) i jednoczesne połączenia (5 $ za każde 100 tysięcy ponad limit). Do testów dostępny jest również tryb emulacji — firebase emulators:start — który uruchamia Realtime Database lokalnie bez połączenia z chmurą.
Realtime Database nie ma tabel, kolekcji ani dokumentów — wszystko jest jednym drzewem JSON dostępnym pod adresem URL w formie https://project-name-default-rtdb.firebaseio.com/. Każdy klucz drzewa to albo wartość końcowa (ciąg znaków, liczba, boolean, null), albo zagnieżdżony węzeł z kluczami potomnymi. Silnik bazy danych nie obsługuje JOIN, podzapytań ani agregacji — zapytanie zawsze zwraca zawartość jednego węzła ze wszystkimi elementami potomnymi.
Z powodu braku JOIN w Realtime Database normalizacja danych jest obowiązkowa. Zamiast zagnieżdżonego drzewa (użytkownik → lista jego postów) dane są dzielone na płaskie listy z odnośnikami przez klucze. Jest to standardowe podejście: dane są denormalizowane, aby odczyt jednego węzła nie ściągał całego kontekstu. Na przykład lista wiadomości czatu jest przechowywana oddzielnie od profili użytkowników, a każdy post zawiera tylko ID autora, a nie cały jego profil.
| Podejście | Przykład struktury | Problem |
|---|---|---|
| Zagnieżdżone | users/{uid}/posts/{postId}/content | Odczyt user ładuje wszystkie posty |
| Płaskie | posts/{postId}/authorId + users/{uid}/name | Wymaga dwóch zapytań |
| Denormalizowane | posts/{postId}/authorName (skopiowane) | Duplikacja przy aktualizacji |
Zapytania w Realtime Database są wykonywane za pomocą filter (orderByChild, orderByKey, orderByValue, limitToFirst, limitToLast, equalTo, startAt, endAt). W przeciwieństwie do Firestore, indeksy są tworzone ręcznie w sekcji Rules (.indexOn). Jeśli indeks nie jest zadeklarowany, zapytanie z sortowaniem zwraca błąd PERMISSION_DENIED. Zapytania działają tylko po jednym polu — zapytania złożone (filtr po cenie + sortowanie po dacie) nie są obsługiwane. W przypadku złożonego filtrowania dane są często duplikowane w różnych węzłach z różnymi kluczami sortowania.
Wybór między Realtime Database a Firestore to jedna z częstych decyzji architektonicznych przy rozpoczynaniu projektu. Google zaleca Firestore dla większości nowych aplikacji, ale Realtime Database pozostaje najlepszym wyborem w scenariuszach, gdzie krytyczne jest minimalne opóźnienie transmisji danych.
Pierwszy scenariusz — gry wieloosobowe z synchronizacją stanu (szachy, gry karciane, akcje w czasie rzeczywistym). Opóźnienie Realtime Database wynosi 10-30 ms wobec 50-100 ms dla Firestore w tym samym regionie. Drugi scenariusz — czaty i komunikatory z wysoką częstotliwością wiadomości. Realtime Database jest taryfikowana według objętości danych, a nie liczby zapisów, co czyni ją znacznie tańszą od Firestore przy częstotliwości powyżej 1 wiadomości na sekundę. Trzeci scenariusz — obecność (presence) użytkowników online/offline, gdzie procedury obsługi onDisconnect w Realtime Database pozwalają atomowo ustawić status przy zerwaniu połączenia.
Według danych Google (2026), około 15% nowych projektów Firebase świadomie wybiera Realtime Database — gdy zespół jasno rozumie wymagania dotyczące opóźnienia, struktury danych i budżetu. W pozostałych 85% przypadków Firestore jest bezpieczniejszym wyborem dzięki lepszej skalowalności, wydajniejszym zapytaniom i automatycznej replikacji.
Podłączenie Realtime Database do aplikacji Android wykonuje się przez dodanie zależności firebase-database-ktx w build.gradle. Obiekt FirebaseDatabase jest dostępny przez getInstance(url) — można połączyć się z wieloma bazami w ramach jednego projektu Firebase. Po inicjalizacji SDK automatycznie ustanawia połączenie WebSocket z serwerem i rozpoczyna synchronizację danych.
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
implementation("com.google.firebase:firebase-database-ktx")
}
// Inicjalizacja z niestandardowym URL
val database = FirebaseDatabase.getInstance(
"https://my-project-default-rtdb.firebaseio.com/"
)
val ref = database.getReference("chats")
Realtime Database używa obiektu DatabaseReference do wszystkich operacji. setValue() zapisuje dane w określonym węźle, całkowicie zastępując całą jego zawartość. push() automatycznie generuje unikalny klucz (na podstawie znacznika czasu) w celu dodania elementu do listy — jest to standardowy sposób tworzenia wiadomości czatu, postów i rekordów. updateChildren() zmienia kilka węzłów atomowo w jednej operacji. addValueEventListener subskrybuje zmiany węzła i otrzymuje callback przy każdej aktualizacji danych.
data class Message(
val author: String = "",
val text: String = "",
val timestamp: Long = ServerValue.TIMESTAMP
)
class ChatRepository(private val ref: DatabaseReference) {
fun sendMessage(author: String, text: String) {
val msg = Message(author = author, text = text)
ref.child("messages").push().setValue(msg)
}
fun observeMessages(): Flow<List<Message>> = callbackFlow {
val listener = ref.child("messages")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val messages = snapshot.children.mapNotNull { it.getValue(Message::class.java) }
trySend(messages)
}
override fun onCancelled(error: DatabaseError) {}
})
awaitClose { ref.removeEventListener(listener) }
}
}
Mechanizm synchronizacji Realtime Database opiera się na protokole WebSocket (wcześniej — long-polling). Klient wysyła żądanie subskrypcji określonego węzła, a serwer utrzymuje połączenie otwarte. Przy każdej zmianie danych w subskrybowanym węźle serwer wysyła klientowi pełny JSON tego węzła. SDK po stronie klienta automatycznie aktualizuje stan lokalny i wywołuje odpowiednie callback-i (onDataChange).
OnDisconnect — unikalna możliwość Realtime Database, niedostępna w Firestore. Deweloper może zarejestrować operację zapisu, która zostanie wykonana na serwerze automatycznie przy zerwaniu połączenia klienta. Jest to używane do statusów obecności: "user123/status": "online" z onDisconnect.setValue("offline"). Jeśli użytkownik zamknął aplikację lub stracił internet, serwer automatycznie ustawi status "offline" nie później niż za 3 minuty (konfigurowalne w konsoli Firebase).
Persistence w Realtime Database włącza się jednym wierszem: FirebaseDatabase.getInstance().setPersistenceEnabled(true). SDK buforuje ostatni stan wszystkich subskrybowanych węzłów na dysku (domyślnie do 10 MiB, konfigurowalne do 100 MiB). W przypadku utraty połączenia klient kontynuuje pracę z danymi z pamięci podręcznej, a wszystkie operacje zapisu są kolejkowane. Po przywróceniu połączenia SDK wysyła wszystkie zgromadzone zmiany na serwer w odpowiedniej kolejności (FIFO).
Według danych Google (2026), aplikacje z włączoną pamięcią podręczną persistence tracą dane użytkowników przy zerwaniu połączenia o 40% rzadziej. Jeśli jednak klient zgromadził ponad 1000 odroczonych operacji, serwer może odrzucić je wszystkie i zażądać pełnej synchronizacji — jest to mechanizm ochronny przed nieaktualnymi klientami.
Security Rules w Realtime Database to konfiguracja JSON opisująca, kto i pod jakimi warunkami może czytać i zapisywać dane w każdym węźle. Zasady działają na serwerze Google i są wykonywane przed każdą operacją. Domyślnie (w produkcji) zaleca się ustawienie reguł w trybie "zamkniętym" — tylko uwierzytelnieni użytkownicy mają dostęp.
Zasady Realtime Database są pisane w formacie JSON z sekcjami .read, .write, .validate, .indexOn. W przeciwieństwie do Firestore (który używa składni match), Realtime Database używa zagnieżdżonych obiektów, odzwierciedlających strukturę danych. Warunki sprawdzają auth (uwierzytelnienie), data (istniejące dane), newData (nowe dane przy zapisie) i now (czas serwera). Reguły walidacji (.validate) pozwalają sprawdzać typy, zakresy wartości i strukturę danych.
{
"rules": {
"users": {
"$uid": {
".read": "auth.uid === $uid",
".write": "auth.uid === $uid",
".validate": "newData.hasChildren(['name', 'email'])"
}
},
"messages": {
".indexOn": ["timestamp"],
"$msgId": {
".read": true,
".write": "auth.uid !== null",
".validate": "newData.child('text').isString() && newData.child('text').val().length <= 500"
}
}
}
}
Zasady Realtime Database są dziedziczone kaskadowo — jeśli na najwyższym poziomie .read = false, to wszystkie węzły potomne są niedostępne do odczytu niezależnie od ich własnych reguł. Firebase udostępnia symulator reguł w konsoli, gdzie można przetestować operacje z różnymi tokenami auth przed wdrożeniem. Zaleca się zawsze testować reguły w symulatorze — błąd w regule może otworzyć dostęp do prywatnych danych wszystkich użytkowników. Według danych Google (2026), 40% wycieków danych w projektach Firebase jest spowodowanych nieprawidłowo skonfigurowanymi regułami bezpieczeństwa.
Często zadawane pytania
Do 200 tysięcy jednoczesnych połączeń z jedną instancją bazy danych. Po przekroczeniu limitu nowe połączenia są blokowane. Do skalowania używa się shardowania na kilka baz.
Użyj onDisconnect — zarejestruj operację zapisu "offline" przy zerwaniu połączenia. Serwer automatycznie ją wykona przy przerwaniu WebSocket. Osobno śledź połączenie przez .info/connected.
Sprawdź .indexOn w Security Rules — bez zadeklarowanego indeksu zapytanie z orderByChild zwróci PERMISSION_DENIED. Upewnij się również, że dane są zapisywane we właściwym węźle, a czytelnik ma uprawnienia .read.
Firebase Console udostępnia eksport z Realtime Database do Firestore jednym przyciskiem. Struktura JSON jest przekształcana w kolekcje i dokumenty. Do niestandardowej migracji użyj Admin SDK.
Nie, przechowywanie haseł w Realtime Database jest zabronione przez zasady bezpieczeństwa Google. Użyj Firebase Auth do uwierzytelniania — hashe haseł są przechowywane w izolowanym magazynie, niedostępnym przez SDK Realtime Database.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również