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

How to Build an Auction or Bidding System in FlutterFlow

Build a live auction system using a Firestore auctions collection with currentBid, currentBidderId, endTime, and a bids subcollection logging every bid. Display auctions with real-time countdown timers, validate bids server-side in a Cloud Function using Firestore transactions to prevent race conditions, and end auctions automatically with a scheduled Cloud Function that sets the status to ended and notifies the winner.

What you'll learn

  • How to model auctions and bids in Firestore with real-time updates
  • How to build a countdown timer that updates every second
  • How to validate bids server-side with Firestore transactions to prevent race conditions
  • How to automatically end auctions and notify winners via Cloud Functions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner10 min read25-35 minFlutterFlow Free+ (Cloud Functions required for bid validation)March 2026RapidDev Engineering Team
TL;DR

Build a live auction system using a Firestore auctions collection with currentBid, currentBidderId, endTime, and a bids subcollection logging every bid. Display auctions with real-time countdown timers, validate bids server-side in a Cloud Function using Firestore transactions to prevent race conditions, and end auctions automatically with a scheduled Cloud Function that sets the status to ended and notifies the winner.

Live auction platform with real-time bidding and countdown timers

An auction system needs real-time updates, countdown pressure, and bulletproof bid validation. This tutorial builds one in FlutterFlow: a Firestore collection stores auction items with current bid and end time, a bids subcollection logs every bid, countdown timers create urgency, a Cloud Function validates bids atomically to prevent two simultaneous bids from overwriting each other, and a scheduled function ends auctions and notifies winners. The result is a functional live auction platform.

Prerequisites

  • A FlutterFlow project with Firebase/Firestore connected
  • Firebase Authentication enabled with user sign-in working
  • Cloud Functions enabled for bid validation and auction ending
  • Understanding of Custom Functions, Action Flows, and real-time Backend Queries

Step-by-step guide

1

Create the Firestore data model for auctions and bids

Create an auctions collection with fields: title (String), description (String), imageUrl (String), startingPrice (Double), currentBid (Double, initially same as startingPrice), currentBidderId (String, initially empty), minIncrement (Double: minimum amount above current bid, e.g., 5.00), endTime (Timestamp), status (String: 'active', 'ended'), bidCount (Integer, default 0), and sellerId (String). Under each auction, create a bids subcollection with fields: userId (String), displayName (String), amount (Double), and timestamp (Timestamp). Set Firestore rules: any authenticated user can read auctions and bids, but only Cloud Functions can write to the currentBid, currentBidderId, and status fields (to prevent client manipulation). Users can read but not directly write auction documents.

Expected result: Firestore has auctions and bids subcollection with proper fields and security rules restricting writes to Cloud Functions.

2

Build the auction listing page with countdown timers

Create an AuctionsPage with a ListView bound to a Backend Query on auctions where status equals 'active', ordered by endTime ascending (ending soonest first). Set Single Time Query to OFF for real-time updates so new bids update the currentBid display live. Each auction card Component shows: Image (imageUrl), title Text, current bid Text (bold, large, prefixed with currency symbol), bidCount Text ('12 bids'), and a countdown timer. For the countdown, create a Custom Function named getTimeRemaining that takes endTime Timestamp and returns a formatted string like '2h 15m 30s' or 'Ending soon!' when under 5 minutes. To update every second, use a Timer Custom Action that re-calculates the countdown every 1000ms and updates a Component State variable. Style items ending within 5 minutes with a red border for urgency. Tap navigates to AuctionDetailPage.

Expected result: Active auctions display with real-time current bids and countdown timers that tick every second. Items ending soon are highlighted.

3

Build the auction detail page with bid history and place bid form

Create an AuctionDetailPage receiving the auction document reference. Display the item image as a large hero, title, description, seller info, and prominent current bid display. Set the auction doc Backend Query to real-time (Single Time Query OFF) so the current bid updates live when other users bid. Below, add a bid history section: ListView bound to auctions/{auctionId}/bids ordered by timestamp descending, limit 10. Each row shows the bidder's displayName, bid amount, and relative timestamp. At the bottom, add a sticky Container with: a TextField for the bid amount (number keyboard, hint showing minimum bid: currentBid + minIncrement), and a Place Bid button. The button is disabled (Conditional Enabling) when: the auction has ended (status != 'active'), the user is the seller, or the entered amount is less than currentBid + minIncrement.

Expected result: The auction detail page shows real-time bid updates, scrollable bid history, and a validated bid input form.

4

Validate and place bids through a Cloud Function with Firestore transaction

Create a callable Cloud Function named placeBid that receives auctionId and bidAmount. The function uses a Firestore transaction to: (1) read the current auction document; (2) verify status is 'active'; (3) verify endTime is in the future; (4) verify bidAmount > currentBid + minIncrement; (5) verify the bidder is not the seller; (6) atomically update currentBid, currentBidderId, and increment bidCount; (7) create a bid document in the bids subcollection. The transaction ensures that if two users bid simultaneously, only the valid higher bid succeeds and the other gets an error. In FlutterFlow, wire the Place Bid button to call this Cloud Function via Backend Call. On success, show a SnackBar confirming the bid. On error, show the error message (e.g., 'Someone outbid you' or 'Auction has ended').

place_bid.js
1// Cloud Function: placeBid
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4
5exports.placeBid = functions.https.onCall(async (data, context) => {
6 if (!context.auth) throw new functions.https.HttpsError('unauthenticated', 'Login required');
7 const { auctionId, bidAmount } = data;
8 const uid = context.auth.uid;
9
10 const auctionRef = admin.firestore().collection('auctions').doc(auctionId);
11 const userDoc = await admin.firestore().collection('users').doc(uid).get();
12 const displayName = userDoc.data()?.displayName || 'Anonymous';
13
14 await admin.firestore().runTransaction(async (txn) => {
15 const auction = await txn.get(auctionRef);
16 if (!auction.exists) throw new functions.https.HttpsError('not-found', 'Auction not found');
17 const d = auction.data();
18 if (d.status !== 'active') throw new functions.https.HttpsError('failed-precondition', 'Auction has ended');
19 if (d.endTime.toDate() < new Date()) throw new functions.https.HttpsError('failed-precondition', 'Auction has ended');
20 if (uid === d.sellerId) throw new functions.https.HttpsError('failed-precondition', 'Sellers cannot bid on own items');
21 if (bidAmount <= d.currentBid + d.minIncrement) {
22 throw new functions.https.HttpsError('failed-precondition',
23 `Bid must be at least $${(d.currentBid + d.minIncrement).toFixed(2)}`);
24 }
25 txn.update(auctionRef, {
26 currentBid: bidAmount,
27 currentBidderId: uid,
28 bidCount: admin.firestore.FieldValue.increment(1),
29 });
30 txn.create(auctionRef.collection('bids').doc(), {
31 userId: uid, displayName, amount: bidAmount,
32 timestamp: admin.firestore.FieldValue.serverTimestamp(),
33 });
34 });
35 return { success: true };
36});

Expected result: Bids are validated atomically via Firestore transaction. Simultaneous bids resolve correctly with only the higher bid winning.

5

Automatically end auctions and notify winners

Create a scheduled Cloud Function named endAuctions that runs every minute (or every 5 minutes). It queries auctions where status equals 'active' and endTime is less than or equal to now. For each expired auction, update status to 'ended'. If currentBidderId is not empty (someone bid), create a notification document for the winner at users/{currentBidderId}/notifications with title 'You won!', body including the item title and winning bid amount. Also notify the seller that their item sold. If no one bid (currentBidderId is empty), notify the seller that the auction ended without bids. In the FlutterFlow UI, add Conditional Visibility on the Place Bid section: hide when status equals 'ended'. Show a 'Winner' banner Container when status is 'ended' and currentBidderId is not empty, displaying the winner's name and winning bid.

Expected result: Auctions end automatically when their time expires. Winners and sellers receive notifications. The UI updates to show the final result.

Complete working example

Auction System Architecture
1Firestore Data Model:
2 auctions/{auctionId}
3 title: String ("Vintage Guitar")
4 description: String
5 imageUrl: String
6 startingPrice: Double (100.00)
7 currentBid: Double (275.00)
8 currentBidderId: String ("uid_xyz")
9 minIncrement: Double (5.00)
10 endTime: Timestamp (2026-03-30 18:00 UTC)
11 status: String ("active" | "ended")
12 bidCount: Integer (12)
13 sellerId: String
14 bids/{bidId} (subcollection)
15 userId: String
16 displayName: String ("JaneDoe")
17 amount: Double (275.00)
18 timestamp: Timestamp
19
20Firestore Rules:
21match /auctions/{auctionId} {
22 allow read: if request.auth != null;
23 allow write: if false; // Only Cloud Functions
24}
25match /auctions/{auctionId}/bids/{bidId} {
26 allow read: if request.auth != null;
27 allow write: if false; // Only Cloud Functions
28}
29
30Auction Listing Page:
31 ListView (auctions, status: active, orderBy endTime ASC, real-time)
32 AuctionCard Component
33 Image (imageUrl)
34 Text (title)
35 Text (currentBid, large, bold, "$275.00")
36 Text (bidCount, "12 bids")
37 Text (countdown: "2h 15m 30s", updated every 1s)
38 Red styling when < 5 minutes
39 On Tap Navigate AuctionDetailPage
40
41Auction Detail Page:
42 Image (hero, large)
43 Text (title + description)
44 Text (currentBid, real-time, large)
45 Text (countdown timer)
46 ListView (bid history, last 10, newest first)
47 Row Text(displayName) + Text(amount) + Text(timeAgo)
48 Sticky Bottom Container [Cond. Vis: status == active]
49 TextField (bid amount, min: currentBid + minIncrement)
50 Button ("Place Bid")
51 On Tap Backend Call: placeBid Cloud Function
52 Winner Banner [Cond. Vis: status == ended && currentBidderId != '']
53 Text ("Won by {name} for ${currentBid}")
54
55Cloud Functions:
56 placeBid (callable): Firestore transaction validation + write
57 endAuctions (scheduled, every 1 min): close expired + notify

Common mistakes when building an Auction or Bidding System in FlutterFlow

Why it's a problem: Updating currentBid without a Firestore transaction so two simultaneous bids can overwrite each other

How to avoid: Use a Firestore transaction in the Cloud Function. The transaction reads currentBid, verifies the new bid exceeds it by the minimum increment, and writes atomically. If another bid was placed between the read and write, the transaction retries automatically.

Why it's a problem: Letting clients update auction documents directly instead of through Cloud Functions

How to avoid: Set Firestore rules to block all client writes on auction documents: allow write: if false. Route all bid submissions through the placeBid Cloud Function that validates every rule before writing.

Why it's a problem: Using a client-side timer for auction ending instead of a server-side scheduled function

How to avoid: Use a scheduled Cloud Function that runs every minute, querying active auctions where endTime has passed. Server timestamps are authoritative. The client countdown is just for display; the Cloud Function is the actual enforcement.

Best practices

  • Validate all bids in a Cloud Function with a Firestore transaction to prevent race conditions
  • Block all direct client writes to auction documents via Firestore Security Rules
  • Use real-time Backend Queries (Single Time Query OFF) for live bid updates without page refresh
  • Run a scheduled Cloud Function to end expired auctions authoritatively
  • Display a countdown timer updated every second for urgency, but enforce timing server-side
  • Notify both the winner and seller when an auction ends via in-app notifications
  • Store bidder displayName on each bid document to avoid N+1 user doc lookups in bid history

Still stuck?

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

ChatGPT Prompt

Write a Firebase Cloud Function that handles auction bid placement using a Firestore transaction. It should verify the auction is active, the bid exceeds the current bid plus a minimum increment, and the bidder is not the seller. Create a bid document and update the auction atomically.

FlutterFlow Prompt

Create an auction detail page with a large item image, title, current bid (updating in real time), a countdown timer, a list of recent bids, and a sticky bottom section with a bid amount input and Place Bid button.

Frequently asked questions

How do I build the countdown timer that updates every second?

Create a Custom Function getTimeRemaining that takes the auction's endTime and returns a formatted string. Use a Timer Custom Action (periodic, 1000ms interval) that recalculates the countdown every second and updates a Component State variable. The Text widget binds to this variable and re-renders each tick.

What happens if no one bids on an auction?

The endAuctions Cloud Function checks if currentBidderId is empty after setting status to ended. If empty, it notifies the seller that the auction ended without bids. The UI shows 'No bids' instead of a winner banner. The seller can choose to relist the item.

Can I add a 'Buy Now' price alongside bidding?

Yes. Add a buyNowPrice field on the auction document. Show a Buy Now button that calls a Cloud Function which sets currentBid to buyNowPrice, currentBidderId to the buyer, and status to ended in a transaction. This immediately closes the auction.

How do I extend the auction if a bid comes in during the last minute?

In the placeBid Cloud Function, after a successful bid, check if endTime minus now is less than 60 seconds. If so, extend endTime by 2 minutes. This prevents auction sniping where users wait until the last second to bid.

How do I handle payment after the auction ends?

When the endAuctions function closes an auction with a winner, create a pending_payment document with auctionId, winnerId, amount, and status pending. Send the winner a notification with a Pay Now link that initiates a Stripe Checkout session for the winning bid amount.

Can RapidDev help build a full auction marketplace?

Yes. A production auction platform needs escrow payments, seller verification, dispute resolution, shipping integration, bid increment rules by price range, auction scheduling, and fraud detection. RapidDev can architect the full platform with secure Cloud Functions and payment integrations.

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.