← All Tools

Parse, validate and format international phone numbers in Go. A port of Google's libphonenumber, with no dependencies outside the standard library.

Why phonenumber?

Phone numbers look simple until you have to store one. The same number can be written as 020 7946 0958, +44 (0)20-7946-0958 or tel:+44-20-7946-0958. Whether it is valid depends on a numbering plan that differs in every country and changes every few weeks. Google's libphonenumber is the reference for getting this right, and this is a port of it to Go.

n, err := phonenumber.Parse("020 7946 0958", "GB")
if err != nil {
	return err
}
n.Valid()                           // true
n.Type()                            // phonenumber.FixedLine
n.Format(phonenumber.International) // "+44 20 7946 0958"
n.FormatFrom("US")                  // "011 44 20 7946 0958"

A value type

Number is a small comparable struct. Compare numbers with ==, use them as map keys, and copy them freely. The zero Number means "no number".

No dependencies

The numbering-plan metadata is generated into Go source, with no protobuf and no runtime XML parsing.

Fits the standard library

Number works as a field with encoding/json, in database/sql rows, and with request binders.

Pay for what you use

Each region's patterns are compiled the first time a number from that region is seen. Geocoding, carrier and time zone data only reach your binary if you import them.

Upstream's behaviour

Upstream's own test suite is ported and runs against upstream's test metadata.

Kept current

A daily workflow checks for new upstream releases, regenerates the metadata, runs the tests and tags a patch release.

What's included

Every public class of upstream's Java library has a Go counterpart, with an API that follows Go conventions:

Parsing Validation & number types Formatting Comparing numbers Finding numbers in text Formatting as you type Short & emergency numbers Geocoding Carriers Time zones

Storing numbers

Number encodes as E.164, such as +442079460958, so it drops straight into a struct you send as JSON or save to a database. The zero Number is stored as NULL.

type Contact struct {
	Name  string             `json:"name"`
	Phone phonenumber.Number `json:"phone"`
}

Errors never include the number itself, so they are safe to log.

Where a number is

Three subpackages carry upstream's prefix data. Each embeds its own data, so a program pays for it only if it imports the package:

n, _ := phonenumber.Parse("+44 20 7946 0958", "")
geocoder.Description(n, "en") // "London"
timezone.ForNumber(n)         // ["Europe/London"]

Install

go get uradical.io/go/phonenumber

Requires Go 1.27 or later. Free and Apache 2.0-licensed, the same as upstream. This is an independent port and is not affiliated with Google.

Learn More

For full documentation and source, see the GitHub repository.