Nearby Driver Search Using Redis
Before building this, we looked into how ride-sharing and dispatch systems usually solve nearby driver search. Most rely on tools like Tile38 and H3 which are great, but not exactly lightweight. Given our time and resource constraints, we went with Redis for both caching and Geo-search.
Table of contents
What we needed?
We needed a way to find all drivers within a given radius of a passenger and notify them in real time. The system had to be fast, simple, and easy to build. It also needed to handle frequent location updates (every 3–5 seconds) from each driver, store metadata like vehicle type so we only notify relevant drivers, and keep track of driver availability to avoid sending requests to busy drivers.

Our approach
The idea was pretty simple: push driver locations into Redis, use its Geo queries to find nearby drivers, filter them based on vehicle type and availability, and then notify them instantly.
Each driver periodically updates their location (every 3–5 seconds), which we store in Redis using a Geo-indexed sorted set.
err := redis.GeoAdd(ctx, DriverLocationsKey, &redis.GeoLocation{
Name: update.DriverID.String(),
Longitude: update.Longitude,
Latitude: update.Latitude,
}).Err()
Once locations are continuously updated, the next step is to query for nearby drivers when a passenger requests a ride.
res, err := s.redis.GeoRadius(ctx, DriverLocationsKey, lon, lat, &redis.GeoRadiusQuery{
Radius: radius,
Unit: "km",
Count: 50,
Sort: "ASC",
}).Result()
If no drivers are found or none accept the request, we progressively increase the search radius (up to ~10 km) until a driver accepts the ride. From each batch of nearby drivers, we filter out those who are already busy and only keep drivers matching the requested vehicle type before sending notifications.
Once we have a list of nearby drivers, we start sending WebSocket messages over the already established persistent connections of active drivers. Each message contains the ride details, allowing drivers to instantly decide whether to accept or ignore the request.
{
"type": "RIDE_AVAILABLE",
"payload": {
"ride_id": "f08a5586-b5fe-4dd7-a97f-9730e340d9de",
"pickup_lat": 16.312821,
"pickup_lon": 80.421903,
"origin_name": "VIT-AP University",
"destination_name": "PVP Square",
"origin_place_id": "ChIJVRzyQH3yNToRUJiFVM3qkBQ",
"destination_place_id": "ChIJs1fI8q_6NToRmyqExJMuxvQ",
"fare": 231.23,
"duration_second": 2860,
"distance_meter": 21445,
"vehicle_type": "BIKE"
}
}
Since the connection is persistent, drivers receive these requests instantly without polling, keeping latency low and the system responsive and, multiple drivers may receive the same request, but only the first one to accept is assigned the ride.
Why not PostGIS
While systems like PostGIS offer more advanced geospatial capabilities, such as complex spatial queries and precise coordinate projections, they are built on top of relational databases that incur disk I/O and write overhead. This makes them less suitable for ingesting continuous, high-frequency location updates. Redis, being an in-memory store, handles rapid writes and low-latency proximity queries more efficiently for this use case. Its built-in geospatial commands (GEOADD, GEOSEARCH) are well-suited for real-time 'find nearby' operations, though with the trade-off of approximate precision based on Geohash encoding. For our requirements of frequent location updates and fast proximity lookups, Redis offered the better balance of speed and simplicity.
Limitations
Redis works well for what we needed, but it does come with some trade-offs worth being aware of.
The most notable one is data durability. Since Redis is an in-memory store, driver locations are not persisted to disk by default. A restart or crash means all location data is lost until drivers start sending updates again. For a live system, this is mostly fine since locations go stale quickly anyway, but it is still something to keep in mind.
Another limitation is the approximate nature of Redis's geospatial queries. Internally, Redis encodes coordinates using Geohash, which introduces a small margin of error (up to around 0.6 meters). For ride-sharing proximity lookups this is completely acceptable, but it would not be suitable for use cases requiring precise boundary calculations.
Finally, Redis's geospatial support is intentionally simple. It handles radius and bounding-box queries well, but anything more complex like polygon-based zones, geofencing with irregular boundaries, or spatial joins would require either additional logic in application code or a proper geospatial database.
For our current scale and requirements, none of these were blockers. But they are the natural next problems to solve as the system grows.
Further reading