Most postcode APIs meter you: a free tier, a credit card wall, then per-request pricing. The data underneath them is largely public domain. That gap felt wrong, so we built postcode.xwira.tech — no signup, no tier, no meter.
This is how it works.
The data: GeoNames, treated with respect
GeoNames publishes postal-code datasets for most of the world. The raw dumps are charmingly old-school: tab-separated files, one country per file, plus one giant allCountries.zip.
Our loaders do three jobs before anything reaches the database:
- Normalize — postcodes get uppercased and de-spaced per country convention; place names keep their original diacritics with an ASCII shadow column for search.
- Dedupe — GeoNames sometimes carries the same code+place pair from multiple sources; we keep the richest row.
- Bulk load — everything goes in through chunked
COPY, not row-by-row INSERTs. Reloading a country is minutes, not hours.
The whole dataset — 8.6M places across 60+ countries — lives comfortably in a few GB of PostgreSQL.
The database: boring on purpose
PostgreSQL, run by the CloudNativePG operator on our Kubernetes cluster. No exotic search engine. Two decisions make it fast enough that we never miss one:
- A composite index on
(country, postcode)makes exact lookups effectively free. - Trigram indexes (
pg_trgm) on place names give fuzzy search — typo-tolerant "Kuala Lumpr" still finds Kuala Lumpur — without running a separate search cluster.
A rule we keep re-learning: add infrastructure only when a query plan tells you to, not when a blog post does.
The API: a small Bun service
The API is a stateless Bun service — start time in milliseconds, tiny image, and one process handles far more traffic than a free community API ever sees. Endpoints follow the questions people actually ask:
GET /search?code=50450— what place is this?GET /search?q=petaling— what codes does this place have?GET /nearby?lat=…&lng=…— what's around me?
Responses are flat JSON. No envelopes, no HATEOAS ceremony — the response should look like what you'd design in your head.
The edge
Traefik terminates TLS with certificates auto-issued by cert-manager and Let's Encrypt. Rate limiting lives here too — generous for humans, firm enough that one runaway script can't ruin the free lunch for everyone.
Every box in the diagram is a container on a self-hosted Kubernetes cluster, declared in version-controlled manifests. Databases are backed up nightly. The web UI at postcode.xwira.tech is a Next.js app that consumes the exact same public API you would — it has no privileged path.
Why free works
The honest math: public-domain data + one small always-on service + boring PostgreSQL ≈ pocket-money hosting costs. The expensive part of commercial postcode APIs was never the compute — it's the business wrapped around it. Remove the business, and free is just… the price.
Want the same lookup from your own code? It's one curl away — no key needed. Start at postcode.xwira.tech.