Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when syncing real-time data, structuring JSON trees, reading/writing, creating listeners, enabling offline persistence, managing presence, sharding, or writing security rules.
.claude/skills/evanca-firebase-database/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 64% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 60% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 36% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 69% | 0% |
This skill defines how to correctly implement Firebase Realtime Database in Flutter applications, covering data modeling, queries, real-time sync, offline support, and security rules.
Use this skill when working with Firebase Realtime Database for simple data models, low-latency sync, or presence functionality. For rich data models requiring complex queries and high scalability, use Cloud Firestore instead.
Choose Realtime Database when the app needs:
Choose Cloud Firestore instead for rich data models requiring queryability, scalability, and high availability.
flutter pub add firebase_databasedartimport 'package:firebase_database/firebase_database.dart'; // After Firebase.initializeApp(): final DatabaseReference ref = FirebaseDatabase.instance.ref();
dartFirebaseDatabase.instance.setPersistenceEnabled(true); FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000); // 10MB
Firebase.initializeApp() completes before accessing FirebaseDatabase.instance.dartfinal newPostKey = FirebaseDatabase.instance.ref().child('posts').push().key;
. $ # [ ] / or ASCII control characters 0-31 or 127.dart// Instead of nesting chat messages inside rooms: // rooms/roomId/messages/messageId/... // Flatten into separate top-level paths: // rooms/roomId: { name: "General", createdBy: "uid1" } // room-members/roomId: { uid1: true, uid2: true } // room-messages/roomId/messageId: { text: "Hello", sender: "uid1", timestamp: ... }
This pattern allows reading room metadata without downloading all messages.
.indexOn in security rules to index frequently queried fields:json{ "rules": { "dinosaurs": { ".indexOn": ["height", "length"] } } }
orderByChild(), orderByKey(), or orderByValue():dartfinal query = FirebaseDatabase.instance.ref("dinosaurs").orderByChild("height");
limitToFirst() or limitToLast():dartfinal query = ref.orderByChild("height").limitToFirst(10);
startAt(), endAt(), and equalTo():dart// Find users whose name starts with "A" final query = ref.child("users") .orderByChild("name") .startAt("A") .endAt("A\uf8ff");
Read once:
dartfinal snapshot = await FirebaseDatabase.instance.ref('users/123').get(); if (snapshot.exists) { print(snapshot.value); }
Real-time listener:
dartfinal subscription = FirebaseDatabase.instance .ref('users/123') .onValue .listen((event) { final data = event.snapshot.value; print(data); }); // Cancel when no longer needed: subscription.cancel();
A DatabaseEvent fires every time data changes at the reference, including changes to children.
Write (replace):
dartawait ref.set({ "name": "John", "age": 18, "created_at": ServerValue.timestamp, });
Update (partial):
dartawait ref.update({"age": 19});
Atomic transaction:
dartfinal result = await FirebaseDatabase.instance .ref('posts/123/likes') .runTransaction((currentValue) { return Transaction.success((currentValue as int? ?? 0) + 1); }); print('Likes: ${result.snapshot.value}');
Multi-path atomic update:
dartfinal updates = <String, dynamic>{ 'posts/$postId': postData, 'user-posts/$uid/$postId': postData, }; await FirebaseDatabase.instance.ref().update(updates);
dartawait FirebaseDatabase.instance.ref('posts/123/timestamp').set(ServerValue.timestamp);
dartFirebaseDatabase.instance.setPersistenceEnabled(true); // Keep critical paths synced when offline FirebaseDatabase.instance.ref('important-data').keepSynced(true);
dart// Detect connection state FirebaseDatabase.instance.ref('.info/connected').onValue.listen((event) { final connected = event.snapshot.value as bool? ?? false; if (connected) { // Set online status and configure onDisconnect cleanup final presenceRef = FirebaseDatabase.instance.ref('status/${uid}'); presenceRef.set({'online': true, 'last_seen': ServerValue.timestamp}); presenceRef.onDisconnect().set({ 'online': false, 'last_seen': ServerValue.timestamp, }); } });
onValue) to read data and get notified of updates — optimized for online/offline transitions.get() only when data is needed once; it probes local cache if the server is unavailable.onDisconnect() operations are executed server-side, ensuring cleanup even if the app crashes.json{ "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } } }
.read, .write, .validate, and .indexOn to control access and validate data.auth variable to authenticate users in security rules.json{ "rules": { "messages": { "$messageId": { ".validate": "newData.hasChildren(['text', 'sender', 'timestamp'])", "text": { ".validate": "newData.isString() && newData.val().length <= 500" } } } } }
Other measured skills in the registry, with their headline benchmark lift.