Use when syncing real-time data, structuring JSON trees, reading/writing, creating listeners, enabling offline persistence, managing presence, sharding, or writing security rules.
npx skills add https://github.com/evanca/flutter-ai-rules --skill firebase-database
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_database
import 'package:firebase_database/firebase_database.dart';
// After Firebase.initializeApp():
final DatabaseReference ref = FirebaseDatabase.instance.ref();
FirebaseDatabase.instance.setPersistenceEnabled(true);
FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000); // 10MB
Firebase.initializeApp() completes before accessing FirebaseDatabase.instance.final newPostKey = FirebaseDatabase.instance.ref().child('posts').push().key;
. $ # [ ] / or ASCII control characters 0-31 or 127.// 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:{
"rules": {
"dinosaurs": {
".indexOn": ["height", "length"]
}
}
}
orderByChild(), orderByKey(), or orderByValue():final query = FirebaseDatabase.instance.ref("dinosaurs").orderByChild("height");
limitToFirst() or limitToLast():final query = ref.orderByChild("height").limitToFirst(10);
startAt(), endAt(), and equalTo():// Find users whose name starts with "A"
final query = ref.child("users")
.orderByChild("name")
.startAt("A")
.endAt("A\uf8ff");
Read once:
final snapshot = await FirebaseDatabase.instance.ref('users/123').get();
if (snapshot.exists) {
print(snapshot.value);
}
Real-time listener:
final 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):
await ref.set({
"name": "John",
"age": 18,
"created_at": ServerValue.timestamp,
});
Update (partial):
await ref.update({"age": 19});
Atomic transaction:
final 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:
final updates = <String, dynamic>{
'posts/$postId': postData,
'user-posts/$uid/$postId': postData,
};
await FirebaseDatabase.instance.ref().update(updates);
await FirebaseDatabase.instance.ref('posts/123/timestamp').set(ServerValue.timestamp);
FirebaseDatabase.instance.setPersistenceEnabled(true);
// Keep critical paths synced when offline
FirebaseDatabase.instance.ref('important-data').keepSynced(true);
// 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.{
"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.{
"rules": {
"messages": {
"$messageId": {
".validate": "newData.hasChildren(['text', 'sender', 'timestamp'])",
"text": {
".validate": "newData.isString() && newData.val().length <= 500"
}
}
}
}
}
Create reversible, focused database migrations with proper naming, version control practices, and zero-downtime deployment considerations. Use this skill when creating or editing migration files in database/migrations/, when writing schema changes (creating/modifying tables, columns, indexes, foreign keys), when implementing migration rollback methods, when managing database version control, when adding or modifying indexes on large tables, or when separating schema changes from data migrations for safer deployments.
Use when importing or exporting vehicle data from/to log files (MDF/MF4/DAT, BLF, ASC/TXT), decoding CAN/CAN FD/LIN messages to signals via DBC, ARXML, or LDF databases, writing timetable data to MDF or BLF files, or calling blfread, blfinfo, blfwrite, mdfRead, mdfWrite, mdfCreate, mdfInfo, canSignalImport, canMessageImport, canMessageTimetable, canFDMessageTimetable, canSignalTimetable, or linMessageTimetable.
>- Sets up, manages, and executes queries against Cloud Firestore database instances. You MUST unconditionally activate this skill if you plan to use Firestore in any way. Use when listing or creating Firestore databases, configuring security rules, designing data models, writing client SDK queries, or checking indexes.
Work with CWICR database across 9 languages. Cross-language matching, translation, and regional pricing.
> Voice, style, and content rules for writing ClickHouse docs. Use when drafting new pages, rewriting sections, or applying editorial polish. Covers identity, voice, pacing, sentence habits, anti-patterns, AI-ism removal, prose tightening, editorial instinct, linking, keywords, content integrity, and marketing site alignment.
Queries PharmGKB / CPIC / DPWG for drug-gene interactions; calls CYP2D6/CYP2C9/CYP2C19/DPYD/TPMT/NUDT15/UGT1A1/SLCO1B1 star alleles and phenotype with PharmCAT, Cyrius (CYP2D6 structural variants), Aldy, Stargazer; applies Caudle 2020 activity-score translation. Use when implementing pharmacogenomic-guided prescribing, applying CPIC vs DPWG guidance, screening HLA risk alleles for ICI / antiepileptics / abacavir, or interpreting compound TPMT+NUDT15 thiopurine risk.
Develop EPLAN Electric P8 scripts, API extensions, and remote-control applications. Use when writing C# scripts for EPLAN (actions, event handlers, ribbon), accessing the EPLAN API (parts database, projects, pages), building external apps that drive EPLAN via Remote Client, or debugging EPLAN automation issues (blocking, threading, dispose). Covers EPLAN 2022–2025.
> Expert in building Datalog queries for Logseq DB graphs. Auto-invokes when users need help writing Logseq queries, understanding Datalog syntax, optimizing query performance, or working with the Datascript query engine. Covers advanced query patterns, pull syntax, aggregations, and DB-specific query techniques.
Take evanca/firebase-database from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.