Low Level Design: Carpooling System

Carpooling systems share many building blocks with on-demand ride-sharing but add significant complexity: multiple passengers must be matched to a single driver route, pickups and dropoffs must be sequenced optimally, and pricing must be split fairly while keeping each passenger’s cost below a solo ride. This post covers the core subsystems.

Route Matching

A passenger submits origin, destination, and departure time window (e.g., ±15 minutes). The system must find drivers whose planned routes can accommodate this passenger without excessive detour.

The matching query uses a spatial corridor approach: the passenger’s direct route is converted to a buffered polyline (typically 2-3 km buffer). Drivers whose origin-destination lines intersect this corridor are candidates. This is implemented using PostGIS with ST_DWithin on the driver’s route geometry.

Candidates are then filtered by departure time overlap and detour threshold before ranking by combined score of detour ratio, departure time delta, and driver rating. Pre-scheduled carpools (e.g., daily commutes) are stored as recurring routes and matched against a trip template rather than a single point-in-time query.

Detour Calculation

For each candidate driver-passenger pair, the system computes detour cost:

detour_ratio = (route_with_passenger - original_route) / original_route

A passenger is acceptable if detour_ratio < 0.3 (30% longer) AND the absolute detour is less than 10 minutes of additional driving time. Both conditions must hold.

When adding a second or third passenger, detour is recomputed for the combined route including all existing passengers. The marginal detour for each additional passenger must independently pass the threshold. This prevents a scenario where two small detours compound into an unacceptable total deviation.

Detour computation calls the routing API for each candidate pair. To bound latency, candidates are pre-filtered by a cheaper geospatial query before routing API calls are made. Routing results are cached for 10 minutes keyed on origin-destination geohash pairs.

Seat Availability

Each driver vehicle has a declared capacity (typically 3 passenger seats). Seat availability is tracked as:

available_seats = vehicle_capacity - current_passengers

This count is stored in Redis and updated atomically using DECR on booking confirmation. A Lua script enforces the hard limit: the seat count is checked and decremented in a single atomic operation to prevent race conditions from concurrent bookings.

If a passenger cancels, seats are returned via INCR. The trip record in the database is the source of truth; Redis is rebuilt from the database on service restart. A booking that fails the Redis check returns a "carpool full" error without writing to the database.

Route Optimization

With multiple passengers, the order of pickups and dropoffs matters significantly for total trip time. This is a variant of the Vehicle Routing Problem (VRP).

For up to 4 passengers, the system uses a nearest insertion heuristic: start with the driver’s origin, iteratively insert the next pickup or dropoff that minimizes added route length. This runs in O(n²) which is fast enough for n ≤ 8 stops.

Constraints enforced during optimization:

  • A passenger’s pickup must occur before their dropoff.
  • No passenger’s total trip time (pickup to dropoff) may exceed 1.5x their solo ride time.
  • Departure time must fall within each passenger’s declared window.

For popular commute corridors, route combinations are pre-computed nightly and cached. When a new booking arrives for a known corridor, the pre-computed insertion point is used instead of running the full heuristic.

Price Splitting

Each passenger’s fare is computed as:

fare = (base_route_cost / passenger_count) + individual_detour_contribution

The individual detour contribution is the marginal routing cost caused by adding that specific passenger, distributed as a surcharge on their fare. This ensures passengers who require greater detour pay slightly more, while all passengers still pay less than a solo ride.

The driver’s total earnings equal the sum of all passenger fares minus the platform commission. Because multiple passengers share the base cost, the driver earns more per kilometer than a solo trip despite each passenger paying less. This is the economic incentive that makes carpooling viable for both sides.

Fare estimates are shown to both driver and each passenger before confirmation. The driver sees total expected earnings; each passenger sees only their own fare.

Booking State Machine

Each passenger booking within a carpool has its own state: matched → confirmed → active → completed. The carpool trip as a whole also has aggregate state. A cancellation by one passenger does not cancel the trip; seats are released and may be rebooked by another passenger.

Cancellation policy:

  • More than 1 hour before departure: full refund, no penalty.
  • 15-60 minutes before departure: partial refund (50%).
  • Within 15 minutes or after driver has started: no refund, cancellation fee applied.

Late cancellations affect the passenger’s reliability score, which influences their priority in future matching. Drivers can see a passenger’s cancellation history before accepting the match.

Passenger Coordination

All passengers in a carpool share a departure time window of ±5 minutes. The driver app shows the ordered list of pickups with estimated arrival time at each stop. Passengers see the driver’s live location and an ETA to their pickup point.

Late-passenger policy: the driver is required to wait 2 minutes beyond the scheduled pickup time. After 2 minutes, the driver may mark the passenger as a no-show and proceed. The no-show is recorded against the passenger’s account. Three no-shows within 90 days reduce the passenger’s matching priority, making it harder to book carpools during peak hours.

Remaining passengers are notified of the no-show event and their fare may be recalculated if the no-show passenger’s seat contributed to cost sharing.

Real-Time Updates

All passengers in a carpool session receive the same driver location stream. The backend maintains a carpool_group entity that maps a trip to all active passenger WebSocket sessions. When the driver’s GPS update arrives via MQTT or WebSocket, the backend fans out the location event to all sessions in the group using a pub/sub channel keyed on carpool:{trip_id}.

Redis Pub/Sub handles the fanout within a single region. For multi-region deployments, the carpool group’s "home" region is determined at booking time and all passengers connect to that region’s WebSocket endpoint. The driver app also receives pickup sequence updates and passenger status notifications (boarded, no-show) via the same WebSocket connection.

See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering

See also: Lyft Interview Guide 2026: Rideshare Engineering, Real-Time Dispatch, and Safety Systems

Scroll to Top