Creating Leaderboards In Firebase For Flutter Games

By Hashim Rahees, 18 min read, May 10 2026

Creating Leaderboards In Firebase For Flutter Games

When I first started building Flutter games, one of the features I always wanted was an online leaderboard. Watching players compete against each other creates a completely different feeling compared to offline score systems. Even a simple arcade game becomes more exciting when players can compare scores globally. People naturally want to reach the top position, beat their friends, and improve their ranking. That competitive feeling increases replay value massively.

During my early experiments, I tried storing scores locally inside the device. That worked for testing, but it failed completely for real competition because every player only saw their own data. I needed a system where all players shared scores online in real time. That was when I started learning Firebase.

Firebase became one of the most important tools in my Flutter game development journey. It simplified many backend systems that normally require large server infrastructure. Instead of managing complicated backend code manually, Firebase provided authentication, databases, hosting, analytics, and cloud functions inside one ecosystem.

For leaderboards specifically, Firebase Firestore worked extremely well. Firestore stores structured online data and synchronizes it across devices. Whenever a player submits a score, the database updates instantly. Other players can immediately see the changes without refreshing the application manually.

One thing I quickly realized is that leaderboard systems are not only about storing scores. A proper leaderboard must handle ranking logic, cheating prevention, optimization, read costs, write costs, timestamps, and support for multiple game types.

My first leaderboard experiment was for a simple Diamond Shooter browser game. Players destroyed falling diamonds and gained points. At the end of every match, the final score uploaded to Firebase. The game then displayed the top players globally.

The first step was creating a Firestore collection for leaderboard data. In Firestore, collections contain documents. Every player score becomes one document inside the leaderboard collection.

FirebaseFirestore.instance .collection('leaderboards') .add({ 'username': 'Hashim', 'score': 540, });

At first this looked extremely simple compared to traditional backend development. Firebase automatically handled online synchronization and storage. But as the project grew larger, I learned there were many important details developers must understand.

One major topic is read and write cost. Firebase is powerful, but Firestore pricing depends heavily on how many database operations happen. Every time the application reads data, it increases read usage. Every time the application writes new data, it increases write usage.

During early testing, I made a mistake that many beginners make. I refreshed the leaderboard constantly every few seconds. This created huge unnecessary read operations. The game worked perfectly, but database usage increased rapidly.

That experience taught me an important lesson about optimization. Firebase applications should minimize unnecessary reads and writes whenever possible.

Instead of loading every score repeatedly, I started limiting leaderboard queries properly. Most games only need the top scores, not thousands of records.

FirebaseFirestore.instance .collection('leaderboards') .orderBy('score', descending: true) .limit(10) .get();

This query loads only the top ten players. The optimization reduced reads significantly while still showing meaningful rankings.

Another thing I learned was avoiding unnecessary writes. Early versions of my games updated the database too often during gameplay. Every small score change triggered a new write request. This was inefficient and expensive.

Later I changed the system completely. Instead of updating scores continuously, the game only uploaded the final score after the match ended. This reduced write operations massively.

Optimization becomes extremely important when browser games start attracting larger audiences. Small inefficiencies may look harmless during testing, but they become expensive with thousands of players.

Another important concept I learned was Firebase timestamps. Time matters a lot in online games because leaderboards often need to sort recent scores or track submission times.

Earlier, I stored device time manually using local clocks. That created problems because players could manipulate their device time settings. Firebase timestamps solved this issue because the server generates reliable time automatically.

FirebaseFirestore.instance .collection('leaderboards') .add({ 'username': 'Hashim', 'score': 540, 'createdAt': FieldValue.serverTimestamp(), });

This ensures the timestamp comes directly from Firebase servers instead of the player device. That creates much more reliable data.

Timestamps became extremely useful later when I added weekly competitions. The game could now filter scores submitted during specific periods. Every week, players competed for the highest score within the new season.

Another challenge appeared when I started supporting different game types. Some games use score based leaderboards while others use time based leaderboards.

In Diamond Shooter, higher scores are better. But in racing games, lower completion times are better. Puzzle games may rank players by fastest completion speed. Endless runners may rank players by distance traveled.

Supporting multiple leaderboard systems required flexible database structure. Instead of creating one rigid format, I designed the leaderboard model carefully.

{ "username": "Hashim", "game": "Diamond Shooter", "score": 540, "completionTime": null, "createdAt": timestamp }

For score based games, the score field becomes important. For racing games, the completionTime field becomes important instead.

In racing games, sorting works differently because lower times should appear first.

FirebaseFirestore.instance .collection('leaderboards') .orderBy('completionTime') .limit(10) .get();

This query shows the fastest players instead of the highest scores.

One thing I truly enjoy about Firebase is how quickly prototypes become functional. Earlier, online backend systems looked terrifying to me because they required server management, database configuration, and API development. Firebase simplified much of that process.

But as projects became more serious, I learned that Firebase functions are extremely important for maintaining secure systems.

Firebase functions allow developers to run backend logic securely on Google servers. This became necessary because leaderboard systems can easily be abused if all logic exists directly inside the client application.

During one of my early browser games, I discovered how easy cheating becomes. Players could modify scores directly from browser developer tools because the validation existed only inside the Flutter application.

Firebase functions helped solve this issue. Instead of trusting the client completely, score validation moved to secure backend logic.

For example, if a player suddenly submits an impossible score, the Firebase function can reject it automatically.

Functions also became useful for ranking calculations. Instead of forcing every client to calculate leaderboard positions repeatedly, the server handled heavy logic centrally.

Another useful system was limiting duplicate submissions. Earlier, players could spam the database repeatedly with the same score. Firebase functions allowed the backend to check whether the new score actually deserved updating.

I also started using Firebase functions for seasonal resets. Every week, the leaderboard automatically archived old rankings and created fresh competitions. This created recurring engagement because players returned regularly for new challenges.

One of the most important lessons I learned about Firestore is that database structure affects performance heavily. Poor structure increases reads, slows queries, and creates scaling problems.

At first, I stored all game scores inside one massive collection. Later I realized separating games into individual collections improved organization significantly.

For example, Diamond Shooter used one collection while racing games used another collection.

leaderboards_diamond_shooter leaderboards_racing_game leaderboards_endless_runner

This structure reduced unnecessary filtering and improved scalability.

Another thing I optimized was pagination. Some games eventually collected thousands of scores. Loading every document at once became inefficient. Instead, I started loading small sections gradually.

This reduced read costs and improved loading speed significantly. Browser games especially benefit from lightweight database usage because players expect fast experiences.

I also learned about offline caching. Firebase can cache leaderboard data locally, which reduces repeated reads when players revisit screens. This improved performance while reducing costs at the same time.

Another major challenge in leaderboard systems is handling player identity. Anonymous score submissions become messy very quickly because duplicate names appear frequently.

Firebase Authentication solved this issue beautifully. Players could sign in using Google accounts or anonymous login systems. Every score became connected to a unique player identifier.

Once authentication existed, I added profile images and country information beside leaderboard scores. The competition immediately felt more social and alive.

Browser gaming communities love competitive systems because they naturally encourage sharing. Players post screenshots of rankings and challenge friends to beat their records.

Another optimization technique I started using was storing only the best score for each player instead of saving every attempt. Earlier, repeated matches created huge database growth unnecessarily.

After changing the logic, the game only updated the database when a player achieved a new personal record.

if(newScore > oldScore) { updateLeaderboard(); }

This simple optimization reduced write operations significantly while keeping the leaderboard cleaner.

One of my favorite things about Firebase leaderboards is real time synchronization. Watching rankings update live creates excitement during competitions. When someone reaches first place, other players instantly see the change.

This real time feeling makes browser arcade games much more engaging compared to isolated offline experiences.

Over time, I realized leaderboard systems are not only technical features. They strongly affect player psychology. Rankings create goals, competition, and replay motivation. Even very simple games become addictive when players chase higher positions.

Looking back, Firebase completely transformed the way I approached multiplayer and online systems in Flutter games. Earlier, backend development felt overwhelming. After learning Firestore and Firebase functions, building connected experiences became much more achievable.

For beginner developers, my advice is to start small. Create simple score submissions first. Then gradually learn optimization, timestamps, security rules, Firebase functions, and multi game leaderboard structures.

Understanding read and write cost early is extremely important. Many beginners accidentally create expensive systems because they refresh data too often or write unnecessary updates constantly.

Firebase is incredibly powerful, but efficient architecture matters. Optimized queries, proper limits, secure functions, and structured collections create scalable systems that perform well even with large player bases.

At the end of the day, leaderboards make games feel alive. They connect players together through competition and achievement. Whether the game uses score rankings, speed runs, racing times, or survival records, online leaderboards create stronger engagement and longer lasting gameplay experiences.