Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Set Up a Fantasy Sports League Platform in FlutterFlow

Create a fantasy sports league platform with leagues, teams, player drafting, and automated scoring. Store leagues with member rosters, a player database with real-world stats, and a draft system using Firestore transactions to prevent duplicate picks. Cloud Functions update player fantasy points after real games and recalculate team totals. Add a trade proposal system for roster management between teams.

What you'll learn

  • How to create a league and team management system with Firestore
  • How to build a live player draft with Firestore transactions preventing duplicate picks
  • How to automate scoring with Cloud Functions that process real-game statistics
  • How to implement a trade proposal system between teams in the same league
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read30-35 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Create a fantasy sports league platform with leagues, teams, player drafting, and automated scoring. Store leagues with member rosters, a player database with real-world stats, and a draft system using Firestore transactions to prevent duplicate picks. Cloud Functions update player fantasy points after real games and recalculate team totals. Add a trade proposal system for roster management between teams.

Building a Fantasy Sports League Platform in FlutterFlow

Fantasy sports apps let users create leagues, draft real-world athletes, build rosters, and compete based on actual game performance. This tutorial builds the core platform: league creation, a live draft system, roster management, automated scoring via Cloud Functions, league leaderboards, and team-to-team trading.

Prerequisites

  • A FlutterFlow project with Firebase authentication enabled
  • Firestore database configured in your Firebase project
  • Cloud Functions enabled on the Firebase Blaze plan
  • A sports data API or manual player database for athlete statistics

Step-by-step guide

1

Create the Firestore schema for leagues, teams, and players

Create a `leagues` collection with fields: name (String), sport (String: football/basketball/baseball), maxTeams (Integer), draftDate (Timestamp), ownerId (String), memberIds (List of Strings), status (String: drafting/active/completed). Add a `teams` subcollection under each league with fields: userId (String), teamName (String), roster (List of Maps with playerId and position), totalPoints (Double). Create a top-level `players` collection with fields: name (String), realTeam (String), position (String), stats (Map with sport-specific fields like touchdowns, yards, rebounds), fantasyPoints (Double), isDrafted (Boolean), leagueId (String). Register all collections in FlutterFlow's Data panel.

Expected result: Three collections are set up: leagues with a teams subcollection, and a top-level players collection with stats and fantasy point fields.

2

Build the league creation and join flow

Create a Leagues page with a ListView showing leagues the current user belongs to (filtered by arrayContains on memberIds). Add a FloatingActionButton to create a new league: a BottomSheet form with TextFields for league name, a DropDown for sport type, a number input for max teams, and a DateTimePicker for draft date. On create, add the current user to memberIds and set them as ownerId. For joining, add a Join League page where users enter a league invite code (use the Firestore document ID as the code). On join, add the user's UID to the league's memberIds array and create a team document in the teams subcollection with a default team name and empty roster.

Expected result: Users can create leagues with custom settings and join existing leagues via an invite code. Each member gets a team document automatically.

3

Implement the live player draft with transaction-based picking

Create a DraftBoard page that receives leagueId as a parameter. At the top, show a Text displaying whose turn it is (calculated by round-robin order of memberIds). Below, add a ListView of available players — query the players collection where isDrafted == false for this league, filterable by position ChoiceChips (QB/RB/WR/TE/K for football). Each player card shows name, team, position, and projected points. Add a Draft Player button on each card. On tap, call a Cloud Function that uses a Firestore transaction: read the player document → verify isDrafted is still false → set isDrafted to true and leagueId → add the player to the drafting user's roster array on their team document → advance the draft turn. The transaction prevents two users from drafting the same player simultaneously.

functions/draftPlayer.js
1// Cloud Function: Draft a player with transaction
2exports.draftPlayer = functions.https.onCall(async (data, context) => {
3 const { leagueId, playerId, position } = data;
4 const uid = context.auth.uid;
5 const db = admin.firestore();
6
7 return db.runTransaction(async (txn) => {
8 const playerRef = db.collection('players').doc(playerId);
9 const playerDoc = await txn.get(playerRef);
10 const player = playerDoc.data();
11
12 if (player.isDrafted && player.leagueId === leagueId) {
13 throw new functions.https.HttpsError(
14 'already-exists', 'Player already drafted');
15 }
16
17 // Mark player as drafted
18 txn.update(playerRef, {
19 isDrafted: true,
20 leagueId: leagueId,
21 });
22
23 // Add to user's roster
24 const teamQuery = await db
25 .collection(`leagues/${leagueId}/teams`)
26 .where('userId', '==', uid).limit(1).get();
27 const teamRef = teamQuery.docs[0].ref;
28
29 txn.update(teamRef, {
30 roster: admin.firestore.FieldValue.arrayUnion({
31 playerId, position, name: player.name,
32 }),
33 });
34
35 return { success: true, player: player.name };
36 });
37});

Expected result: Users draft players in turn order. The transaction ensures no two teams can draft the same player, and the board updates in real time for all participants.

4

Build the roster view and league leaderboard

Create a MyTeam page showing the current user's roster. Add a ListView bound to the team document's roster array. Each item shows the player name, position, real team, and current fantasy points (joined from the players collection). Show a total points Text at the top summing all roster players' fantasy points. For the league leaderboard, create a Standings tab on the league page with a ListView bound to the teams subcollection ordered by totalPoints descending. Each row shows: rank number, team name, owner name, and total points. Highlight the top 3 with gold, silver, and bronze Container styling. Add the current user's team with a 'You' badge for quick identification.

Expected result: Users see their roster with player stats and the league standings ranked by total fantasy points.

5

Automate scoring with a Cloud Function that updates fantasy points

Create a Cloud Function that runs on a schedule (e.g., daily after games) or can be triggered manually by the league admin. The function fetches real-game statistics from your sports data API (or reads from a manually updated stats collection), calculates fantasy points per player using your scoring rules (e.g., 6 points per touchdown, 1 point per 10 yards), updates each player's fantasyPoints field, then recalculates totalPoints for every team in every active league by summing their roster players' fantasy points. Update the team documents with the new totals. This keeps the leaderboard current without any manual intervention.

Expected result: After real games conclude, the Cloud Function updates player fantasy points and recalculates team totals, automatically updating the leaderboard.

6

Add a trade proposal system between teams

Create a `trades` subcollection under each league with fields: proposerTeamId (String), receiverTeamId (String), offeredPlayerIds (List), requestedPlayerIds (List), status (String: pending/accepted/rejected), timestamp (Timestamp). On the roster page, add a Trade button that opens a TradeProposal page. The user selects players from their roster to offer and players from the opponent's roster to request. On submit, create a trade document with status 'pending'. The receiving team sees the proposal in a Trades Inbox ListView. On accept, a Cloud Function atomically swaps the players between rosters using a batch write. On reject, update the status. Add a trade deadline field on the league document after which trades are disabled.

Expected result: Teams can propose player trades. The receiving team reviews and accepts or rejects. Accepted trades atomically swap players between rosters.

Complete working example

FlutterFlow Action Flow — Fantasy Sports League System
1// Firestore Schema
2// Collection: leagues
3// - name: String
4// - sport: String (football | basketball | baseball)
5// - maxTeams: Integer
6// - draftDate: Timestamp
7// - ownerId: String
8// - memberIds: List<String>
9// - status: String (drafting | active | completed)
10// - tradeDeadline: Timestamp
11
12// Subcollection: leagues/{id}/teams
13// - userId: String
14// - teamName: String
15// - roster: List<Map> [{playerId, position, name}]
16// - totalPoints: Double
17
18// Collection: players
19// - name: String
20// - realTeam: String
21// - position: String (QB | RB | WR | TE | K)
22// - stats: Map {touchdowns, yards, receptions...}
23// - fantasyPoints: Double
24// - isDrafted: Boolean
25// - leagueId: String
26
27// Subcollection: leagues/{id}/trades
28// - proposerTeamId: String
29// - receiverTeamId: String
30// - offeredPlayerIds: List<String>
31// - requestedPlayerIds: List<String>
32// - status: String (pending | accepted | rejected)
33// - timestamp: Timestamp
34
35// Page: DraftBoard
36// Layout: Column
37// → Text "Round {X} — {userName}'s Pick"
38// → ChoiceChips (position filter: All, QB, RB, WR, TE, K)
39// → ListView (available players, isDrafted==false)
40// → Container (player card)
41// → Row: Text(name) + Text(position) + Text(team)
42// → Row: Text(projectedPoints) + Button("Draft")
43// → Bottom: Text "Your Roster: {count}/15 players"
44
45// Draft Action Flow:
46// 1. Button tap → API Call to draftPlayer Cloud Function
47// params: leagueId, playerId, position
48// 2. Cloud Function: Firestore transaction
49// - Read player → verify not drafted
50// - Update player: isDrafted=true, leagueId
51// - Update team roster: arrayUnion(player)
52// - Advance draft turn
53// 3. On success → SnackBar "Drafted {playerName}!"
54// 4. Real-time listener updates available players list
55
56// Scoring Cloud Function (scheduled):
57// 1. Fetch game stats from sports API
58// 2. For each player: calculate fantasyPoints
59// e.g. touchdowns*6 + yards/10 + receptions*1
60// 3. Update player.fantasyPoints
61// 4. For each active league → each team:
62// sum roster players' fantasyPoints → update totalPoints

Common mistakes

Why it's a problem: Not using a Firestore transaction when drafting players

How to avoid: Route all draft picks through a Cloud Function that uses a Firestore transaction to atomically read the player status, verify availability, and assign to the team.

Why it's a problem: Calculating team total points on the client side by summing roster player points

How to avoid: Use a Cloud Function to recalculate totalPoints on team documents whenever player fantasyPoints are updated. The client reads a single pre-computed value.

Why it's a problem: Storing player draft status globally instead of per-league

How to avoid: Track draft status per league by combining isDrafted with leagueId, or use a draftedInLeagues array. When checking availability, filter by the current league.

Best practices

  • Use Firestore transactions for all draft operations to prevent duplicate picks
  • Store scoring rules in a Firestore config document so different leagues can customize point values
  • Denormalize player names on the roster array to avoid extra lookups when displaying the team
  • Set real-time listeners on the draft board so all participants see picks as they happen
  • Implement a trade deadline after which all trade proposals are automatically rejected
  • Calculate and store team total points server-side to ensure consistency across all clients
  • Add a waiver wire system for undrafted players available after the draft completes

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I'm building a fantasy sports league platform in FlutterFlow with Firestore. I need league creation with invite codes, a live player draft with Firestore transactions preventing duplicate picks, roster management, automated scoring via Cloud Functions, a leaderboard, and a trade proposal system. Show me the Firestore schema and Cloud Function for the draft.

FlutterFlow Prompt

Create a draft board page with position filter ChoiceChips and a ListView of available players. Each player card shows name, position, team, and projected points with a Draft button. Show whose turn it is at the top.

Frequently asked questions

How do I populate the players collection with real athlete data?

Use a sports data API like ESPN, SportRadar, or MySportsFeed. Create a Cloud Function that fetches player data and writes it to the players collection. Alternatively, manually import data via CSV upload to Firestore.

Can I support multiple sports in one app?

Yes. Use the sport field on the league document to determine which player pool and scoring rules to use. Create separate scoring configs per sport in Firestore.

How does the draft turn order work?

Use a round-robin snake draft: in round 1, pick order is 1-2-3-4, in round 2 it reverses to 4-3-2-1, and so on. Store the current pick index on the league document and advance it in the draft Cloud Function.

Can I add a salary cap for roster building?

Yes. Add a salaryValue field to each player and a salaryCap field to the league. In the draft transaction, check that the team's total salary plus the new player's value does not exceed the cap before allowing the pick.

How do I handle players who get injured during the season?

Add an injuryStatus field to the player document (healthy, questionable, out, IR). Display this on roster and draft views. Allow teams to move injured players to an IR slot and pick up replacement players from the waiver wire.

Can RapidDev help build a production fantasy sports platform?

Yes. RapidDev can implement live draft rooms with real-time chat, automated scoring integrations with sports data APIs, advanced trade systems, playoff brackets, and mobile push notifications for game-day alerts.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.