# Geocoder: the Ruby gem that puts coordinates on your ActiveRecord models

> A MIT-licensed Ruby library that wraps more than 40 geocoding APIs behind one call, adds latitude and longitude columns to your models, and turns proximity into a database scope.

**alexreisner/geocoder** — Complete Ruby geocoding solution.

- Repository: https://github.com/alexreisner/geocoder
- Website: http://www.rubygeocoder.com
- Stars: 6,447 · Forks: 1,197
- Language: Ruby
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/alexreisner-geocoder

## Wiring geocoded_by into an ActiveRecord model

The whole library can be understood from one example. A model needs three things: a method that returns something geocodable, somewhere to store the coordinates, and one line telling the gem where to look. The first can be a single attribute or an assembled string:

```ruby
def address
  [street, city, state, country].compact.join(', ')
end
```

Second, the model needs two float or decimal columns named `latitude` and `longitude` for ActiveRecord. MongoDB is different, because it wants a single Array field called `coordinates`. Third, the declaration itself:

```ruby
geocoded_by :address
```

That line adds a `geocode` method to the model, which you wire to a callback so records are located when they are validated:

```ruby
after_validation :geocode
```

Reverse geocoding follows the same shape, taking the coordinate columns instead of an address method:

```ruby
reverse_geocoded_by :latitude, :longitude
after_validation :reverse_geocode
```

Once objects are geocoded they carry distance and bearing methods: `obj.distance_to([43.9,-98.6])`, `obj.bearing_to([43.9,-98.6])` and `obj.bearing_from(obj2)`. The bearing methods take a coordinate array, another geocoded object, or an address string, and the distance methods take a units argument of `:mi`, `:km` or `:nm`. Outside Rails, with ActiveRecord on Sinatra or Padrino, the model needs `extend Geocoder::Model::ActiveRecord` before those methods exist.

## Forward, reverse and IP lookups through one entry point

The simplest call takes a string and returns results, each of which knows its own coordinates:

```ruby
results = Geocoder.search("Paris")
results.first.coordinates
# => [48.856614, 2.3522219]  # latitude and longitude
```

The same method reverses. Hand it an array and it returns addresses:

```ruby
results = Geocoder.search([48.856614, 2.3522219])
results.first.address
+# => "Hôtel de Ville, 75004 Paris, France"
```

And it will locate an IP address without you saying which kind of lookup you want:

```ruby
results = Geocoder.search("172.56.21.89")
results.first.coordinates
+# => [30.267153, -97.7430608]
results.first.country
+# => "United States"
```

That last example is worth pausing on. The single `search` method dispatches on what it is given, which is convenient and also the source of the library's main risk: the provider you configured is used for every kind of query, so an IP lookup through a geocoding API may behave differently than an address lookup through the same one.

The README is blunt about the accuracy question. It says success and accuracy of geocoding depends entirely on the API being used, that most queries work fairly well with the default configuration, and that every API has its particular strengths and weaknesses. It points to the API Guide, split out into `README_API_GUIDE.md`, as the place to see the supported providers.

## Turning proximity into an ActiveRecord scope

Once models carry coordinates, the useful part is querying by location, and that is done with scopes rather than by pulling records into Ruby and computing distances yourself:

```ruby
Venue.near('Omaha, NE, US')                   # venues within 20 miles of Omaha
Venue.near([40.71, -100.23], 50)              # venues within 50 miles of a point
Venue.near([40.71, -100.23], 50, units: :km)  # venues within 50 kilometres of a point
Venue.geocoded                                # venues with coordinates
Venue.not_geocoded                            # venues without coordinates
```

The default radius is 20 miles, and the units argument switches the query to kilometres, which is the version most of the world wants. The two state scopes are the practical ones: `not_geocoded` is how you find the records whose lookup failed, which is exactly the population you need to requeue.

On a geocoded object itself, the same idea is available without a collection:

```ruby
if obj.geocoded?
  obj.nearbys(30)                       # other objects within 30 miles
  obj.distance_from([40.714,-100.234])  # distance from an arbitrary point
+end
+```

This works because the README lists support for MySQL, PostgreSQL, SQLite and MongoDB, and for Rails 5.x through 8.x. The database doing the filtering is what keeps a nearby search from turning into a full table scan in your application code. SQLite is the interesting edge of that list, since spatial indexing there is more limited than in MySQL or PostgreSQL, and a large dataset on SQLite will feel the difference long before it does on Postgres.

## The MongoDB coordinate order trap

One section of the README exists purely to warn you, and it is worth reading before you use this gem with MongoDB. Geocoder expects coordinate arrays in the order `[lat, lon]` everywhere in its own API. MongoDB stores positions longitude-first, following the GeoJSON specification, so internally the gem stores them backwards.

The gem tries to hide this. `obj.to_coordinates`, added by `geocoded_by`, returns the conventional order:

```ruby
obj.to_coordinates  # => [37.7941013, -122.3951096] # [lat, lon]
```

Reading the attribute directly does not:

```ruby
obj.coordinates     # => [-122.3951096, 37.7941013] # [lon, lat]
```

So the failure mode is quiet: code that queries with one convention and reads the raw field with another produces points in the ocean off the coast of Indonesia instead of San Francisco. The README's own advice is a warning rather than a fix, so the rule worth adopting in your codebase is to go through the gem's methods and never touch the raw attribute.

MongoDB users have one extra setup step, since the module has to be included before `geocoded_by` will do anything:

```ruby
include Geocoder::Model::Mongoid
include Geocoder::Model::MongoMapper
+```

Mongoid and MongoMapper are separate includes, so pick the one matching your object document mapper.

## Performance work lives in examples and bin

The README is organised as a long table of contents, and the sections past the basics are where a production deployment actually gets decided: Performance and Optimization, Advanced Model Configuration, Advanced Database Queries, Geospatial Calculations, Batch Geocoding, Testing, Error Handling, and a Command Line Interface.

The repository tree backs those sections up. There is a `bin/` directory for the CLI, a `test/` directory, a `gemfiles/` directory for testing against multiple Bundler setups, a `Rakefile`, an `init.rb` for Rails initialisers, and `geocoder.gemspec` for the gem metadata. The `examples/` directory holds three files with telling names: `app_defined_lookup_services.rb`, `cache_bypass.rb` and `reverse_geocode_job.rb`.

Those three examples describe most of what makes geocoding slow. Bypassing the cache, defining your own lookup service rather than the configured provider's, and running reverse geocodes as a background job instead of inside a request cycle. Each one addresses a specific cost: a duplicated network call, a provider that does not suit your data, or a user waiting on an HTTP round trip.

Testing also gets its own README section, which is a rarer signal than it sounds. Geocoding calls a third-party API over HTTP, and a test suite that really hits the network is a flaky test suite, so how the gem lets you stub lookups matters more here than in most libraries. Worth noting is what is not in the repository: there are no published GitHub releases, so the version history lives in `CHANGELOG.md` rather than in release tags.

## Where the gem stops and the provider starts

Geocoder is not a geocoding service. It has no data of its own, no index and no API key. Every coordinate it returns came from someone else's request, and the README says so in the first section by insisting that accuracy depends entirely on the API being used.

That boundary shapes the comparison with alternatives. A direct HTTP client against one provider's endpoint is less code for a project that only needs address lookup and never stores coordinates. A server-side spatial database such as PostGIS is a better answer for radius queries over large datasets. What Geocoder replaces is the whole layer in between: model mixins, provider configuration, caching, the distance calculations and the ActiveRecord scopes, which you would otherwise assemble yourself for each new project.

The compatibility numbers are also worth reading as constraints rather than claims. Ruby 2.5 and later plus JRuby, MySQL, PostgreSQL, SQLite and MongoDB, Rails 5.x to 8.x, and outside Rails with the `json` gem on MRI or `json_pure` on JRuby. The last push was on 2026-08-09 and the licence is MIT, so there is no cost or permission question about using it in a commercial codebase. The documentation site is rubygeocoder.com, and the API provider list is `README_API_GUIDE.md` in the repository.

## Conclusion

Geocoder earns its place in a Rails application the moment a user can type an address or click a map, because it removes the need to write a provider client, a retry policy and a distance query by hand. Its real limits are the ones it is honest about: quality comes from whichever API you configure, coordinates for MongoDB are stored in the opposite order to how every method accepts them, and caching is your problem once you leave a default configuration. Add the gem, run `geocoded_by :address` on one model, then read the API guide before choosing a lookup, since that choice is what determines whether your results are any good.

## FAQ

### What does a geocoder do?

It converts between an address and a pair of coordinates. The geocoder gem does this for you in Ruby through a single `Geocoder.search` call, and it can do it in both directions: hand it a string such as Paris and the results expose `.coordinates`, hand it a coordinate array and the results expose `.address`. It also locates IP addresses the same way, and it can attach coordinates to ActiveRecord models so you can query them by distance.

### How do I find the geocode of my address in Ruby?

Call `Geocoder.search` with the address and read the coordinates off the first result, for example `Geocoder.search("Paris").first.coordinates`, which the README shows returning `[48.856614, 2.3522219]`. In a Rails model, add `latitude` and `longitude` columns, declare `geocoded_by :address`, and use an `after_validation :geocode` callback so records are located as they save.

### Does the geocoder gem store geocoding data, or does it call an external API?

It calls an external API. The gem has no geographic data of its own; it connects to more than 40 APIs worldwide and normalises their responses into result objects. The README is explicit that success and accuracy depend entirely on the API being used, which is why the API guide covers provider strengths and weaknesses. The gem stores results in your database only because you choose to add coordinates columns to your models.

## Sources

- [alexreisner/geocoder on GitHub](https://github.com/alexreisner/geocoder)
- [Issues](https://github.com/alexreisner/geocoder/issues)
- [License: MIT](https://github.com/alexreisner/geocoder/blob/master/LICENSE)
- [Project website](http://www.rubygeocoder.com)
- [README](https://github.com/alexreisner/geocoder/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/alexreisner-geocoder
