Build a ride-sharing platform with passenger and driver flows. Passengers enter pickup and destination, see a route polyline with estimated fare on a Google Map, and request a ride. A Cloud Function finds the nearest available driver using geoHash proximity queries and assigns the ride. Drivers accept or decline, navigate to pickup, start the ride, and complete it. Live tracking updates the driver marker every 5 seconds. Fare calculation uses distance multiplied by a per-kilometer rate with optional surge pricing.
Building a Ride-Sharing Platform in FlutterFlow
A ride-sharing app connects passengers who need rides with drivers who are available nearby. This tutorial builds both sides: passengers request rides with pickup and destination, drivers receive and accept requests, and the app handles matching, real-time tracking, fare calculation, and ride completion. The matching uses geoHash for finding the nearest available driver.
Prerequisites
- A FlutterFlow project with Firestore, Cloud Functions, and Google Maps configured
- Google Maps Directions API enabled for route polylines
- Google Geocoding API enabled for address-to-coordinates conversion
- Understanding of Custom Actions and Cloud Function triggers
Step-by-step guide
Design the Firestore data model for rides and drivers
Design the Firestore data model for rides and drivers
Create a rides collection with fields: passengerId (String), driverId (String, null until assigned), status (String: requested, accepted, arrivedAtPickup, inProgress, completed, cancelled), pickupLat (double), pickupLng (double), pickupAddress (String), dropoffLat (double), dropoffLng (double), dropoffAddress (String), fare (double), estimatedMinutes (int), distanceKm (double), requestedAt (Timestamp), completedAt (Timestamp). Create a drivers collection: userId (String), displayName (String), vehicleInfo (String), lat (double), lng (double), geoHash (String, precision 5), isAvailable (Boolean), currentRideId (String, null when free), rating (double).
Expected result: Firestore has rides and drivers collections with location and status tracking fields.
Build the passenger ride request flow
Build the passenger ride request flow
Create a PassengerHome page. Add two TextFields: pickup location and destination. Use Google Places Autocomplete via a Custom Action to convert addresses to coordinates as the user types. When both locations are set, display a FlutterFlowGoogleMap showing: a green marker at pickup, a red marker at destination, and a route polyline between them using the Google Directions API. Show a fare estimate card at the bottom: calculate distance from the Directions API response, multiply by a per-km rate (for example 1.50), add a base fare (2.00), and display the estimated total. Add a Request Ride button that creates a rides document with status 'requested' and the coordinates.
Expected result: Passengers see pickup-to-destination route with fare estimate on a map and can request a ride.
Create a Cloud Function to find and assign the nearest driver
Create a Cloud Function to find and assign the nearest driver
Write a Cloud Function triggered on rides document creation where status equals 'requested'. Compute the geoHash of the pickup location at precision 4. Query the drivers collection where geoHash starts with this prefix AND isAvailable equals true. From the results, calculate actual distance to each driver using the Haversine formula and pick the closest one. Update the ride document with driverId and status 'accepted'. Update the driver document: set isAvailable to false and currentRideId to the ride ID. If no driver is found, set status to 'noDriverAvailable' so the passenger sees a retry message.
1// Cloud Function: assignNearestDriver2import * as functions from 'firebase-functions';3import * as admin from 'firebase-admin';4admin.initializeApp();56function haversineKm(lat1: number, lng1: number, lat2: number, lng2: number): number {7 const R = 6371;8 const dLat = (lat2 - lat1) * Math.PI / 180;9 const dLng = (lng2 - lng1) * Math.PI / 180;10 const a = Math.sin(dLat/2)**2 +11 Math.cos(lat1*Math.PI/180) * Math.cos(lat2*Math.PI/180) *12 Math.sin(dLng/2)**2;13 return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));14}1516export const assignNearestDriver = functions.firestore17 .document('rides/{rideId}')18 .onCreate(async (snap, context) => {19 const ride = snap.data();20 const pickupHash = ride.pickupGeoHash.substring(0, 4);21 const driversSnap = await admin.firestore()22 .collection('drivers')23 .where('isAvailable', '==', true)24 .where('geoHash', '>=', pickupHash)25 .where('geoHash', '<', pickupHash + '~')26 .get();2728 if (driversSnap.empty) {29 return snap.ref.update({ status: 'noDriverAvailable' });30 }3132 let nearest = { id: '', dist: Infinity };33 driversSnap.forEach(doc => {34 const d = doc.data();35 const dist = haversineKm(ride.pickupLat, ride.pickupLng, d.lat, d.lng);36 if (dist < nearest.dist) nearest = { id: doc.id, dist };37 });3839 await snap.ref.update({ driverId: nearest.id, status: 'accepted' });40 await admin.firestore().doc(`drivers/${nearest.id}`)41 .update({ isAvailable: false, currentRideId: context.params.rideId });42 });Expected result: When a ride is requested, the Cloud Function automatically finds and assigns the nearest available driver.
Build the driver acceptance and navigation flow
Build the driver acceptance and navigation flow
Create a DriverHome page. Add a real-time listener (Single Time Query OFF) on rides where driverId equals current user and status equals 'accepted'. When a ride appears, show a ride request card: passenger name, pickup address, destination, estimated fare, and distance. Add Accept and Decline buttons. Accept navigates to a DriverNavigation page showing the route to pickup on a Google Map. Add status update buttons: Arrived at Pickup (sets status 'arrivedAtPickup'), Start Ride (sets 'inProgress'), and Complete Ride (sets 'completed'). On completion, set the driver's isAvailable back to true and currentRideId to null.
Expected result: Drivers receive ride requests, navigate to pickup, and progress through ride status stages.
Implement real-time driver location tracking on the map
Implement real-time driver location tracking on the map
While a ride is in 'accepted' or 'inProgress' status, the driver app updates the driver's lat, lng, and geoHash in Firestore every 5 seconds using a Periodic Action that calls the geolocator Custom Action and writes the coordinates. On the passenger's ride tracking page, add a FlutterFlowGoogleMap with a real-time listener on the driver's location document. The driver marker updates its position on every Firestore change, showing movement in near-real-time. Also show the route polyline and estimated arrival time.
Expected result: Passengers see the driver's car marker moving on the map in real time as it approaches pickup and during the ride.
Calculate final fare and handle ride completion
Calculate final fare and handle ride completion
When the driver taps Complete Ride, a Custom Function calculates the final fare. Get the actual distance from the ride route or compute from the GPS trail logged during the ride. Apply the fare formula: baseFare + (distanceKm multiplied by perKmRate) + optional surge multiplier. Update the ride document with the final fare, distanceKm, and completedAt timestamp. Show the passenger a ride summary: map of the route taken, distance, duration, and fare. Add a rating prompt: 5 tappable star icons that update the driver's rating. Create a rating document and recalculate the driver's average rating via Cloud Function.
Expected result: Completed rides show a summary with fare breakdown, and passengers rate their driver.
Complete working example
1FIRESTORE DATA MODEL:2 rides/{rideId}3 passengerId: String4 driverId: String (null until assigned)5 status: "requested" | "accepted" | "arrivedAtPickup" | "inProgress" | "completed" | "cancelled"6 pickupLat: double, pickupLng: double, pickupAddress: String7 dropoffLat: double, dropoffLng: double, dropoffAddress: String8 pickupGeoHash: String (precision 5)9 fare: double10 estimatedMinutes: int11 distanceKm: double12 requestedAt: Timestamp13 completedAt: Timestamp1415 drivers/{driverId}16 userId: String17 displayName: String18 vehicleInfo: String19 lat: double, lng: double20 geoHash: String (precision 5)21 isAvailable: Boolean22 currentRideId: String (null when free)23 rating: double2425FARE CALCULATION:26 baseFare = 2.0027 perKmRate = 1.5028 surgeMutliplier = 1.0 (normal) to 2.5 (peak)29 fare = (baseFare + distanceKm * perKmRate) * surgeMultiplier3031WIDGET TREE — Passenger Request:32 Column33 ├── TextField (pickup, Google Places autocomplete)34 ├── TextField (destination, Google Places autocomplete)35 ├── Expanded36 │ FlutterFlowGoogleMap37 │ markers: pickup (green) + destination (red)38 │ polyline: route from Directions API39 └── Container (fare estimate card)40 Column41 ├── Row (distance + estimated time)42 ├── Text (estimated fare, large bold)43 └── Button 'Request Ride'4445WIDGET TREE — Passenger Tracking:46 Stack47 ├── FlutterFlowGoogleMap48 │ markers: driver (car icon, real-time) + destination (red)49 │ polyline: route50 └── Positioned (bottom)51 Container (ride status card)52 Column53 ├── Text (status: 'Driver is on the way' / 'Ride in progress')54 ├── Text (driver name + vehicle info)55 └── Stepper (requested → accepted → arrived → in progress → completed)5657WIDGET TREE — Driver Home:58 Column59 ├── Text ('Available for Rides')60 ├── Switch (isAvailable toggle)61 └── Conditional (incoming ride request)62 Container (card)63 Column64 ├── Text (pickup address → destination address)65 ├── Text (estimated fare + distance)66 └── Row (Accept button + Decline button)Common mistakes when creating a Ride-Sharing Platform in FlutterFlow
Why it's a problem: Finding the nearest driver with simple lat/lng subtraction instead of proper distance calculation
How to avoid: Use the Haversine formula or Google Distance Matrix API for accurate driving distance between pickup and driver locations.
Why it's a problem: Not handling the case when no drivers are available
How to avoid: Set a timeout in the Cloud Function. If no driver is found within the geoHash search radius, update status to 'noDriverAvailable' and show the passenger a retry option with expanded search area.
Why it's a problem: Updating driver location on every GPS change without throttling
How to avoid: Throttle location updates to once every 5 seconds using a Periodic Action. This provides smooth tracking while keeping Firestore writes manageable.
Best practices
- Use geoHash proximity queries for efficient nearest-driver search in Firestore
- Throttle driver location updates to every 5 seconds to balance accuracy and cost
- Show real-time driver position on the passenger's map with Firestore real-time listeners
- Calculate fares server-side in Cloud Functions to prevent client-side tampering
- Handle no-driver-available gracefully with retry and expanded search radius
- Use a ride status state machine to progress through clear lifecycle stages
- Store route polylines on the ride document to avoid redundant Directions API calls
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a ride-sharing app in FlutterFlow. Passengers enter pickup and destination, see a route with fare estimate, and request a ride. A Cloud Function finds the nearest driver via geoHash. Drivers accept, navigate to pickup, and complete rides. Real-time tracking shows the driver on the map. Show me the data model, Cloud Function for driver matching, and passenger tracking widget tree.
Create a ride request page with two address input fields, a Google Map showing a route between two points, and a card at the bottom showing estimated fare and a Request Ride button.
Frequently asked questions
How do I implement surge pricing during peak hours?
Store a surge_multiplier in a Firestore config document that Cloud Functions can adjust based on ride request volume versus available drivers. Multiply the base fare by this value. Show the multiplier to passengers before they confirm the request.
Can I let passengers cancel rides?
Yes. Add a Cancel button that sets ride status to 'cancelled'. Apply a cancellation fee if the driver has already accepted and traveled toward pickup. Reset the driver's isAvailable to true.
How do I handle multiple ride requests hitting the same driver?
Use a Firestore transaction in the Cloud Function: read the driver's isAvailable, check it is still true, then set it to false and assign the ride. If another request already claimed the driver, the transaction fails and the function picks the next nearest driver.
Can I add ride scheduling for future pickups?
Add a scheduledAt field to the ride. Instead of matching immediately, a scheduled Cloud Function runs periodically and matches rides where scheduledAt is within the next 15 minutes.
How do I calculate the route distance for fare purposes?
Use the Google Directions API distance field from the route response. This gives actual driving distance, not straight-line distance, accounting for roads and turns.
Can RapidDev help build a ride-sharing or logistics platform?
Yes. RapidDev can build ride-sharing and logistics platforms with real-time tracking, driver matching, fare calculation, payment integration, and admin dashboards.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation