How to Sort by Geo Distance Using Bounding Boxes in Algolia
Geo search in Algolia is good at answering one question: “what is closest to this point?” It gets awkward when the product question is really:
- show items within a band, not just inside a circle
- exclude items that are too close
- keep sorting by distance
- do all of it without changing the client
That is the problem this article solves.
The Problem
Imagine a marketplace that shows listings near a user. The product team wants a fallback rail:
- primary rail: items within 30 miles
- secondary rail: items between 30 and 50 miles
- both rails sorted by distance from the user
That second rail is not a standard radius query. It is an annulus: everything outside the inner radius and inside the outer radius.
Algolia can rank by distance, but it does not give you a built-in minimum-radius filter that pairs cleanly with geo sorting.
What Does Not Work Well
aroundRadius Only Solves Half The Problem
Algolia’s geo sorting is centered on aroundLatLng and aroundRadius. That is enough if you want “closest items first” or “everything within X miles.”
It does not solve “between X and Y miles.” There is no native inner-radius filter.
insideBoundingBox Breaks Distance Ranking
A common fallback is to build an outer box with insideBoundingBox and then subtract an inner box.
That sounds promising until you hit the catch: insideBoundingBox and aroundLatLng do not play together the way you want for distance-based ranking. If distance order matters, that tradeoff is usually unacceptable.
Client-Side Workarounds Age Poorly
You could ship the logic to every client and patch the UI there. That is fragile when:
- mobile apps are already deployed
- multiple clients need the same behavior
- the search rule is business logic, not UI logic
This is the kind of rule you want to fix once on the server.
Use Numeric Filters As A Geo Boundary
Algolia stores coordinates in _geoloc.
{
"_geoloc": {
"lat": 47.6062,
"lng": -122.3321
}
}
If your index allows _geoloc.lat and _geoloc.lng as numeric filters, you can build your own bounding boxes.
The approach is:
- sort by distance with
aroundLatLng - set
aroundRadiusto'all' - use numeric filters to keep only the outer box
- subtract the inner box with a second filter expression
A Practical Pattern
A clean way to think about the query is to split it into two predicates:
const withinOuterBox = [
`_geoloc.lat < ${upperLeft.lat}`,
`_geoloc.lat > ${bottomRight.lat}`,
`_geoloc.lng > ${upperLeft.lng}`,
`_geoloc.lng < ${bottomRight.lng}`,
].join(' AND ')
const outsideInnerBox = [
`_geoloc.lat >= ${innerUpperLeft.lat}`,
`_geoloc.lat <= ${innerBottomRight.lat}`,
`_geoloc.lng <= ${innerUpperLeft.lng}`,
`_geoloc.lng >= ${innerBottomRight.lng}`,
].join(' OR ')
const filters = `${withinOuterBox} AND ${outsideInnerBox}`
Then run the search with geo ranking enabled:
index.search('query', {
aroundLatLng: '47.6062, -122.3321',
aroundRadius: 'all',
filters,
})
Why this shape?
aroundLatLngkeeps the results sorted by proximityaroundRadius: 'all'avoids clipping the search too early- the outer box narrows the search space
- the inner-box exclusion removes the nearby items you do not want
Implementation Checklist
Before you ship this approach, check the following:
- your index exposes
_geolocfor every searchable record _geoloc.latand_geoloc.lngare configured as numeric filters- you have a reliable way to compute bounding boxes from a center point and distances
- you test edge cases near the international date line and the poles if your app supports global search
- you confirm your filter syntax with Algolia’s validator before rolling out
Why This Is Worth The Extra Work
This pattern keeps the ranking rule server-side and preserves distance sorting. That matters when the product rule is “show the best nearby alternatives,” not just “show nearby results.”
It is a little more work than a simple radius query, but it is predictable, portable, and easy to reason about once you split the problem into an outer box and an inner exclusion.
