Build Status Coverage Status

This Golang package contains an embedded geocoder. There are no major external dependendies other than some downloaded data files. Once downloaded, those data files are stored in memory. So after the initial load there truly are no outside dependencies. It geocodes and reverse geocodes to a city level detail. It approximates and takes educated guesses when not enough detail is provided. See test cases for more examples.


To keep it short and simple, the reason this package was built was because geocoding services are really expensive. If city level detail is enough and you don't need street addresses, then this should be completely fine. It's also nice that there are no HTTP requests being made to do this (after initial load - and the data files can be copied to other places).

Performance is pretty good, but that is one of the goals. Overtime it should improve, but for now it geocodes a string to lat/lng in about 0.0125 - 0.0135 seconds (on a Macbook Pro).


You should re-use the GeoBed struct as it contains a LOT of data (2.7+ million items). On this struct are the functions to geocode and reverse geocode. Be aware that this also means your machine will need a good bit of RAM since this is all data held in memory (which is also what makes it fast too).

g := NewGeobed()
c := g.Geocode("london")

In the above case, c should end up being:

{London london City of London,Gorad Londan,ILondon,LON,Lakana,Landen,Ljondan,Llundain,Londain,Londan,Londar,Londe,Londen,Londinium,Londino,Londn,London,London City,Londona,Londonas,Londoni,Londono,Londonu,Londra,Londres,Londrez,Londri,Londye,Londyn,Londýn,Lonn,Lontoo,Loundres,Luan GJon,Lunden,Lundra,Lundun,Lundunir,Lundúnir,Lung-dung,Lunnainn,Lunnin,Lunnon,Luân Đôn,Lùng-dŭng,Lākana,Lůndůn,Lọndọnu,Ranana,Rānana,The City,ilantan,landan,landana,leondeon,lndn,london,londoni,lun dui,lun dun,lwndwn,lxndxn,rondon,Łondra,Λονδίνο,Горад Лондан,Лондан,Лондон,Лондонъ,Лёндан,Լոնդոն,לאנדאן,לונדון,لندن,لوندون,لەندەن,ܠܘܢܕܘܢ,लंडन,लंदन,लण्डन,लन्डन्,লন্ডন,લંડન,ଲଣ୍ଡନ,இலண்டன்,లండన్,ಲಂಡನ್,ലണ്ടൻ,ලන්ඩන්,ลอนดอน,ລອນດອນ,ལོན་ཊོན།,လန်ဒန်မြို့,ლონდონი,ለንደን,ᎫᎴ ᏗᏍᎪᏂᎯᏱ,ロンドン,伦敦,倫敦,런던 GB ENG 51.50853 -0.12574 7556900 gcpvj0u6yjcm}

So you can get lat/lng from the GeobedCity struct real easily with: c.Latitude and c.Longitude.

You'll notice some records are larger and contain many alternate names for the city. The free data sets come from Geonames and MaxMind. MaxMind has more but less details. Geonames has more details, but it only contains cities with populations of 1,000 people or greater (about 143,000 records).

If you looked up a major city, you'll likely have information such as population (c.Population).

You can reverse geocode as well.

c := g.ReverseGeocode(30.26715, -97.74306)

This would give you Austin, TX for example.

Data Sets

The data sets are provided by Geonames and MaxMind. These are open source data sets. See their web sites for additional information.

Expand ▾ Collapse ▴




This section is empty.


View Source
var UsSateCodes = map[string]string{
	"AL": "Alabama",
	"AK": "Alaska",
	"AZ": "Arizona",
	"AR": "Arkansas",
	"CA": "California",
	"CO": "Colorado",
	"CT": "Connecticut",
	"DE": "Delaware",
	"FL": "Florida",
	"GA": "Georgia",
	"HI": "Hawaii",
	"ID": "Idaho",
	"IL": "Illinois",
	"IN": "Indiana",
	"IA": "Iowa",
	"KS": "Kansas",
	"KY": "Kentucky",
	"LA": "Louisiana",
	"ME": "Maine",
	"MD": "Maryland",
	"MA": "Massachusetts",
	"MI": "Michigan",
	"MN": "Minnesota",
	"MS": "Mississippi",
	"MO": "Missouri",
	"MT": "Montana",
	"NE": "Nebraska",
	"NV": "Nevada",
	"NH": "New Hampshire",
	"NJ": "New Jersey",
	"NM": "New Mexico",
	"NY": "New York",
	"NC": "North Carolina",
	"ND": "North Dakota",
	"OH": "Ohio",
	"OK": "Oklahoma",
	"OR": "Oregon",
	"PA": "Pennsylvania",
	"RI": "Rhode Island",
	"SC": "South Carolina",
	"SD": "South Dakota",
	"TN": "Tennessee",
	"TX": "Texas",
	"UT": "Utah",
	"VT": "Vermont",
	"VA": "Virginia",
	"WA": "Washington",
	"WV": "West Virginia",
	"WI": "Wisconsin",
	"WY": "Wyoming",

	"AS": "American Samoa",
	"DC": "District of Columbia",
	"FM": "Federated States of Micronesia",
	"GU": "Guam",
	"MH": "Marshall Islands",
	"MP": "Northern Mariana Islands",
	"PW": "Palau",
	"PR": "Puerto Rico",
	"VI": "Virgin Islands",

	"AA": "Armed Forces Americas",
	"AE": "Armed Forces Europe",
	"AP": "Armed Forces Pacific",

A handy map of US state codes to full names.


This section is empty.


type Cities

type Cities []GeobedCity

func (Cities) Len

func (c Cities) Len() int

func (Cities) Less

func (c Cities) Less(i, j int) bool

func (Cities) Swap

func (c Cities) Swap(i, j int)

type CountryInfo

type CountryInfo struct {
	Country            string
	Capital            string
	Area               int32
	Population         int32
	GeonameId          int32
	ISONumeric         int16
	ISO                string
	ISO3               string
	Fips               string
	Continent          string
	Tld                string
	CurrencyCode       string
	CurrencyName       string
	Phone              string
	PostalCodeFormat   string
	PostalCodeRegex    string
	Languages          string
	Neighbours         string
	EquivalentFipsCode string

Information about each country from Geonames including; ISO codes, FIPS, country capital, area (sq km), population, and more. Particularly useful for validating a location string contains a country name which can help the search process. Adding to this info, a slice of partial geohashes to help narrow down reverse geocoding lookups (maps to country buckets).

type GeoBed

type GeoBed struct {
	// contains filtered or unexported fields

Contains all of the city and country data. Cities are split into buckets by country to increase lookup speed when the country is known.

func NewGeobed

func NewGeobed() GeoBed

Creates a new Geobed instance. You do not need more than one. You do not want more than one. There's a fair bit of data to load into memory.

func (*GeoBed) Geocode

func (g *GeoBed) Geocode(n string, opts ...GeocodeOptions) GeobedCity

Forward geocode, location string to lat/lng (returns a struct though)

func (*GeoBed) ReverseGeocode

func (g *GeoBed) ReverseGeocode(lat float64, lng float64) GeobedCity

Reverse geocode

type GeobedCity

type GeobedCity struct {
	City    string
	CityAlt string
	// TODO: Think about converting this to a small int to save on memory allocation. Lookup requests can have the strings converted to the same int if there are any matches.
	// This could make lookup more accurate, easier, and faster even. IF the int uses less bytes than the two letter code string.
	Country    string
	Region     string
	Latitude   float64
	Longitude  float64
	Population int32
	Geohash    string

A combined city struct (the various data sets have different fields, this combines what's available and keeps things smaller).

type GeocodeOptions

type GeocodeOptions struct {
	ExactCity bool

Options when geocoding. For now just an exact match on city name, but there will be potentially other options that can be set to adjust how searching/matching works.

Source Files