If you've ever built anything that touches a backend, you've probably faced this exact problem: given an IP address, figure out where in the world it's coming from. Fraud detection systems need to flag logins from unexpected locations. Ad servers need to target by region. CDNs need to route users to the nearest node. Security auditors need to trace attack origins. And every single one of these use cases shares two non-negotiable requirements: the lookup has to be fast, and it has to be always available — no network flakiness, no third-party outage, no rate limit throttling at the worst possible moment.
This is the problem that ip2region — an open-source project sitting at 19.3K GitHub stars — was built to solve. And it solves it with a design philosophy that's almost stubbornly elegant: pack the entire world's IP-to-location mapping into a single 11-megabyte binary file, then query it locally at ten-microsecond speeds with zero network calls.
Let's unpack why this matters.
The first thing to understand about ip2region is that it's not merely a lookup table. At its core is the xdb engine — a custom binary file format designed from the ground up for IP range storage and retrieval. This isn't JSON. It isn't SQLite. It's a purpose-built, sorted binary structure optimized for one thing: finding which IP range a given address falls into, as fast as physically possible.
The default data format returns results as Country|Province|City|ISP|iso-alpha2-code. Chinese regions are localized in Chinese; everywhere else uses English. But here's where it gets interesting: the region field is fully customizable. You can stuff GPS coordinates, postal codes, ASN numbers, or even your own internal business tags into those fields. In practice, this means ip2region doubles as an IP data management framework — you can maintain your own private IP intelligence database using its toolchain.
The xdb generation programs (available in Go, Java, Python, C#, Rust, and C++) automatically handle the grunt work: merging adjacent IP segments, deduplicating identical region strings, and compressing everything down. The result? A complete global IP geolocation dataset clocks in at just 11 MiB. That's smaller than most Docker base images.
ip2region offers three query modes, and even the slowest one is still in the microsecond range:
| Mode | Memory Overhead | Query Speed | Best For |
|---|---|---|---|
| Pure File | Nearly zero | Tens of microseconds | Memory-constrained environments, embedded systems |
| vIndex Cache | 512 KiB | 10–20 microseconds | Balanced workloads, containerized services |
| Full Memory Load | 11 MiB | Single-digit microseconds | Production services chasing maximum throughput |
Under the hood, the xdb file stores IP ranges as sorted segments. A binary search over those segments — with the optional vector index shaving off one disk I/O — is what makes the lookups so fast. In full-memory mode, you're trading 11 megabytes of RAM for zero disk access on every query. For any production service doing thousands of lookups per second, that trade is a no-brainer.
To put this in perspective: a round-trip to a cloud IP geolocation API typically runs 50–200 milliseconds. ip2region in full-memory mode runs the same query in roughly 10 microseconds. That's 5,000 to 20,000 times faster — and it never hits a rate limit.
One of the quiet strengths of ip2region is its language coverage. The project provides first-party query clients for virtually every mainstream stack:
| Language | IPv4 | IPv6 | xdb Generation |
|---|---|---|---|
| Go | ✅ | ✅ | ✅ |
| Java | ✅ | ✅ | ✅ |
| Python | ✅ | ✅ | ✅ (IPv4) |
| Rust | ✅ | ✅ | ✅ |
| C | ✅ | ✅ | — |
| C++ | ✅ | ✅ | ✅ |
| JavaScript/Node.js | ✅ | ✅ | — |
| C# | ✅ | ✅ | ✅ (IPv4) |
| PHP | ✅ | ✅ | — |
| Lua | ✅ | ✅ | — |
| Erlang | ✅ | ✅ | — |
| Nginx | ✅ | ✅ | — |
| Cangjie | ✅ | ✅ | — |
Third-party community clients add support for Ruby, TypeScript, and Composer (PHP). The unified API is version-compatible, meaning a single query call handles both IPv4 and IPv6 seamlessly.
What's especially practical: the xdb generation programs are available in the same languages as the query clients. If you need to build custom IP datasets — say, mapping IP ranges to your own CDN node assignments — you can do it entirely within your existing stack.
Perfect fit:
Consider alternatives when:
package main
import (
"fmt"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
)
func main() {
searcher, _ := xdb.NewWithFileOnly("ip2region_v4.xdb")
defer searcher.Close()
region, _ := searcher.SearchByStr("8.8.8.8")
fmt.Println(region)
// Output: 美国|0|0|0|Level3
}
from xdb_search import XdbSearcher
with XdbSearcher.content_search("ip2region_v4.xdb") as searcher:
region = searcher.search("8.8.8.8")
print(region)
# Output: 美国|0|0|0|Level3
That's it. Download the ip2region_v4.xdb file (11MB) from the GitHub releases page, pick your language binding, and you're live. The repo includes benchmark test programs for every language — run them yourself and see the microsecond timings firsthand.
ip2region didn't emerge in a vacuum. It's part of a broader shift in how developers are thinking about infrastructure dependencies. SQLite has become the default database for edge computing. DuckDB brought analytical SQL to single-file workflows. Embedded databases like Bolt and Badger power Go services without Postgres. The common thread: bring the data to the compute, not the compute to the data.
For IP geolocation, the old model was: pay MaxMind a recurring license fee, or call a cloud API and pray it doesn't go down during your Black Friday traffic spike. ip2region represents the new model: a single binary file, updated when you choose, queried in microseconds, with no external dependency chain to break.
At 19.3K stars and counting, the community has already voted. Sometimes the best infrastructure is the kind you can hold in 11 megabytes.