cd /news/machine-learning/system-design-surge-pricing-algorith… Β· home β€Ί topics β€Ί machine-learning β€Ί article
[ARTICLE Β· art-29403] src=dev.to β†— pub= topic=machine-learning verified=true sentiment=Β· neutral

[System Design] Surge Pricing Algorithm: How Ride-Hailing Engines Calculate Surge Rate in Real Time

A developer details how ride-hailing platforms like Uber and Grab calculate surge pricing in real time using a demand/supply ratio per H3 hexagon cell, recalculated every 30–60 seconds via a lookup table or ML model. The system ingests driver locations and ride requests through Kafka, aggregates them in Flink, and feeds the ratio into a pricing engine that outputs surge multipliers cached in Redis for rider and driver apps.

read8 min views1 publishedJun 16, 2026

Series context:This is Part 5 of the[Real-Time Ride-Hailing Architecture]series. For location ingestion and geospatial indexing, start at[Part 1].

Surge rate is the real-time price multiplier (e.g., 2.0Γ—) applied by ride-hailing platforms when ride demand in a geographic zone exceeds available driver supply. It is recalculated every 30–60 seconds per H3 hexagon cell using a demand/supply ratio fed into a lookup table or ML model.

{{< faq q="What is surge rate?" >}}

Surge rate (also called surge pricing or surge multiplier) is the real-time price multiplier that ride-hailing platforms like Uber and Grab apply when demand for rides exceeds the available supply of drivers in a geographic zone. A surge rate of 2.0x means the rider pays twice the base fare.

{{< /faq >}}

{{< faq q="How is surge rate calculated?" >}}

The surge rate is calculated by a pricing engine that evaluates the ratio of incoming ride requests (demand) versus available drivers (supply) in a specific H3 hexagon cell over a rolling time window (typically 5 minutes). The ratio is fed into a lookup table or ML model that outputs the surge multiplier.

{{< /faq >}}

On New Year's Eve, during heavy rain, or at rush hour β€” the demand for rides skyrockets, but the number of available drivers remains unchanged. If prices were kept fixed:

Surge Pricing (or Dynamic Pricing) is not merely a tool to increase revenue β€” it is a marketplace equilibrium mechanism:

Price increases β†’ Two simultaneous effects:

1. SUPPLY INCREASES: Drivers see red zones (high prices) on their heatmap
                     β†’ They move toward those areas to earn more
                     β†’ The number of available drivers in the area increases

2. DEMAND DECREASES: Riders see high prices β†’ Some choose to wait, take a bus,
                     or walk β†’ The number of ride requests drops

β†’ Supply and demand gradually return to EQUILIBRIUM
β†’ Wait times are reduced for riders who truly need a car
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      DATA PIPELINE                              β”‚
β”‚                                                                  β”‚
β”‚  Kafka Topic              Flink Stream Processing                β”‚
β”‚  "driver.location"  ───►  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
β”‚  "ride.requests"    ───►  β”‚  Supply-Demand      β”‚                β”‚
β”‚                           β”‚  Aggregator         β”‚                β”‚
β”‚                           β”‚  (per H3 cell,      β”‚                β”‚
β”‚                           β”‚   5-min window)     β”‚                β”‚
β”‚                           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
β”‚                                     β”‚                            β”‚
β”‚                                     β–Ό                            β”‚
β”‚                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
β”‚                           β”‚  Pricing Engine     β”‚                β”‚
β”‚                           β”‚  (Surge Calculator) β”‚                β”‚
β”‚                           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
β”‚                                     β”‚                            β”‚
β”‚                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                β”‚
β”‚                           β”‚  Redis Cache        β”‚                β”‚
β”‚                           β”‚  (Surge Multipliers) β”‚                β”‚
β”‚                           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
β”‚                                     β”‚                            β”‚
β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚                    β–Ό                β–Ό                β–Ό           β”‚
β”‚              Rider App        Driver App       Matching Engine   β”‚
β”‚              (Shows price)    (Heatmap)        (Weighs cost)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Surge pricing is not calculated for an entire city β€” it is calculated for individual H3 hexagons. Uber uses Resolution 7 (each cell ~5 kmΒ²), which is large enough to be statistically significant but small enough to reflect hyper-local conditions.

Ho Chi Minh City is divided into ~200 H3 cells (Resolution 7)

Cell A (District 1 - Center): Supply=5,  Demand=30  β†’ Surge 3.2x
Cell B (District 7 - Suburb): Supply=20, Demand=15  β†’ Surge 1.0x (normal)
Cell C (Airport):             Supply=8,  Demand=40  β†’ Surge 4.0x
Cell D (District 9 - Outskirts): Supply=12, Demand=3   β†’ Surge 1.0x

Just like in e-commerce allocation algorithms that decide which warehouse fulfills an order, the surge engine evaluates resources dynamically.

surge_multiplier = f(demand / supply)

Where:
  supply  = Number of AVAILABLE drivers in the H3 cell (last 5 mins)
  demand  = Number of ride requests in the H3 cell (last 5 mins)

Example simple formula (illustrative):
  ratio = demand / supply

  if ratio <= 1.0:  surge = 1.0 (normal price)
  if ratio == 2.0:  surge = 1.5
  if ratio == 3.0:  surge = 2.0
  if ratio >= 5.0:  surge = 3.5 (maximum cap)

In reality, Uber doesn't use a simple linear formula. They use ML models to calculate optimal prices based on a multitude of factors:

Input Feature Meaning
Supply count Number of idle drivers in the cell
Demand count Number of requests in a sliding window
Historical patterns Supply-demand patterns by hour/day of the week
Weather data Raining β†’ demand rises, supply drops
Events Large events (concerts, football games)?
Conversion rate What % of riders still book at the current surge price?
Neighboring cells Surge levels in adjacent cells (spillover effect)
Continuous feedback loop:

1. Surge = 3.0x β†’ Many riders cancel (conversion rate drops from 70% β†’ 30%)
2. Engine realizes: price is too high, riders are abandoning
3. Lowers surge to 2.0x β†’ Conversion rate recovers to 60%
4. Simultaneously, drivers arrive (supply increases) β†’ ratio drops
5. Surge continues dropping to 1.5x β†’ 1.0x

This entire process happens automatically over a few minutes.

Surge pricing doesn't just affect the cost for the rider β€” it generates a Heatmap displayed on the driver's app, guiding them to areas with high demand.

Heatmap Visualization:

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                                    β”‚
  β”‚      🟒          🟑               β”‚
  β”‚            🟒         🟑          β”‚
  β”‚      🟒   District 7     πŸ”΄       β”‚
  β”‚            🟒    🟑  πŸ”΄ District 1β”‚
  β”‚      🟒        🟑  πŸ”΄ πŸ”΄         β”‚
  β”‚                   πŸ”΄              β”‚
  β”‚               🟑                  β”‚
  β”‚                                    β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  🟒 = 1.0x (normal, surplus of drivers)
  🟑 = 1.5-2.0x (moderate demand)
  πŸ”΄ = 2.5x+ (very high demand, great earning potential)

The heatmap is pushed to the driver app via WebSockets (or gRPC streams):

Server β†’ WebSocket Push β†’ Driver App

Payload every 30 seconds:
{
  "heatmap": [
    {"h3": "872a100d6ffffff", "surge": 3.2, "color": "#FF0000"},
    {"h3": "872a100d7ffffff", "surge": 1.0, "color": "#00FF00"},
    {"h3": "872a100d8ffffff", "surge": 1.8, "color": "#FFAA00"}
  ],
  "updated_at": "2026-05-06T20:30:00Z"
}

Uber and Grab don't just react to current surges β€” they predict surges before they happen:

Predictive Model:

Inputs:
  - Current time: 17:00 (rush hour approaching)
  - Day: Friday (weekend β†’ demand rises)
  - Weather: Rain forecasted at 17:30
  - Events: Concert at the Stadium at 20:00
  - History: The last 4 Fridays also surged to 2.5x at 17:30

Output:
  - Prediction: Surge will hit 2.8x in the Stadium area at 17:30
  - Action: Send notifications to nearby drivers 15 minutes BEFORE
    "High demand expected near the Stadium soon, drive there to earn more!"
Price shown to rider: "Surge 2.5x"
Final Price = Base Fare Γ— 2.5
Problem: Riders didn't know the total cost before getting in β†’ Surprises, complaints
Shown to rider: "Price: 125,000 VND" (fixed before booking)

Price is calculated from:
  base_fare + (distance Γ— per_km_rate) + (time Γ— per_min_rate)
  + surge_premium
  + route_specific_adjustments (e.g., predicted traffic jams)

The rider knows the exact price upfront β†’ Much more transparent
-- Redis: Stores the surge multiplier for each H3 cell
-- Key pattern: surge:{resolution}:{h3_cell_id}
-- TTL: 60 seconds (auto-expires if not updated β†’ falls back to 1.0x)

SET surge:7:872a100d6ffffff "3.2" EX 60
SET surge:7:872a100d7ffffff "1.0" EX 60
SET surge:7:872a100d8ffffff "1.8" EX 60

-- When Rider App requests a price:
GET surge:7:872a100d6ffffff β†’ "3.2"
-- The API Gateway uses this value to calculate the Upfront Price
Risk Solution
Drivers deliberately turning off apps to create artificial scarcity Detect patterns: many drivers going offline simultaneously β†’ flag
Drivers only accepting high surge rides, rejecting normal rides Low acceptance rate β†’ lower priority in matching algorithm
Extremely high surges causing massive backlash Maximum cap (e.g., 5.0x), soft caps based on conversion rates
"Flickering" surge (rapidly fluctuating prices) Smoothing: surge can only increase/decrease by a max of 0.5x every 30 seconds

What is surge rate in ride-hailing?

Surge rate is the multiplier applied to a ride's base price during peak demand periods. A surge rate of 1.5x on a $10 base fare means the rider pays $15. The surge rate is calculated per geographic zone (H3 cell) and updated every 30–60 seconds.

Why does surge rate exist?

Surge rate is a market-clearing mechanism, not just a revenue tool. When demand outpaces supply, a higher surge rate simultaneously attracts more drivers to the area (supply increase) and filters out lower-urgency ride requests (demand decrease), restoring equilibrium and reducing wait times for riders who genuinely need a car.

What is a normal surge rate vs. a high surge rate?

A surge rate of 1.0x is the baseline (no surge). Rates between 1.2x–1.8x are considered moderate surge. Rates above 2.0x indicate heavy demand imbalance. Most platforms enforce a hard cap (e.g., 5.0x) to prevent extreme price spikes that damage user trust.

How long does a surge rate last?

Surge rates are recalculated every 30–60 seconds using a sliding window over the last 5 minutes of supply-demand data. In most cases, a surge event lasts 15–45 minutes before drivers repositioning to the zone restore equilibrium.

How does the surge pricing engine work technically?

The engine ingests driver location events and ride request events from a message broker (Kafka). A stream processor (Apache Flink) aggregates supply and demand counts per H3 cell on a 5-minute tumbling window. The output is a demand/supply ratio that maps to a surge multiplier via a lookup table or an ML model. The resulting multiplier is cached in Redis with a 60-second TTL and read by the API gateway at price-calculation time.

In the final part, we will explore RAMEN β€” Uber's real-time communication infrastructure, which solves the problem of pushing instant notifications to millions of devices simultaneously. Continue reading[Part 6 β€” RAMEN & Real-time Communication].

This post was originally published on my blog at Surge Pricing Algorithm: How Ride-Hailing Engines Calculate Surge Rate in Real Time.

Hi, I'm LΓͺ TuαΊ₯n Anh (vesviet) πŸ‘‹

I am a Senior Go Backend Architect & Distributed Systems Engineer with 17+ years of experience building high-traffic platforms (25M+ requests/month).

If you enjoyed this deep-dive, let's connect on LinkedIn or explore my consulting services at tanhdev.com/hire.

── more in #machine-learning 4 stories Β· sorted by recency
── more on @uber 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/system-design-surge-…] indexed:0 read:8min 2026-06-16 Β· β€”