Parse and normalize international street addresses in pure JavaScript. Zero dependencies, fully typed, and runs anywhere — Node.js, the browser, and edge/serverless runtimes (Vercel, Cloudflare Workers, Deno, Bun).
import { parseAddress } from "anyaddress";
parseAddress("123 Main St, Springfield, IL 62704");
// {
// line1: "123 Main St",
// city: "Springfield",
// region: "IL",
// regionName: "Illinois",
// postalCode: "62704",
// country: "US",
// confidence: 0.95
// }Parsing a free-text address into structured fields in JavaScript is surprisingly painful:
- The accurate option, libpostal, is a C library. Its Node binding (
node-postal) needs a compiler and downloads ~2 GB of ML models — so it won't run on serverless or edge, and it's a nightmare to install in CI. - The pure-JS options are stale or US-only. The most popular (
parse-address) hasn't shipped since 2019 and only handles US addresses.
anyaddress fills the gap: a maintained, pure-JavaScript, no-native-build address parser that handles the common US / Canada / UK / Australia formats — the bulk of real e-commerce and shipping traffic — and degrades gracefully for everything else.
- 🌍 International — US, CA, GB, AU out of the box, with a sensible generic fallback.
- 📦 Zero dependencies — tiny, tree-shakeable, no native build step.
- ⚡ Runs anywhere — Node, browser, edge, serverless. Pure ESM + CJS.
- 🔤 Normalization — standardize casing, street suffixes (
Street → St), and region/postal codes. - 🧭 Country & postal-code detection from the address shape.
- 🧱 Typed — first-class TypeScript types, never throws on junk input.
npm install anyaddressimport { parseAddress } from "anyaddress";
parseAddress("100 Queen St W, Toronto, ON M5H 2N2");
// { line1: "100 Queen St W", city: "Toronto", region: "ON",
// regionName: "Ontario", postalCode: "M5H 2N2", country: "CA", confidence: 0.95 }
parseAddress("12 Oxford Street, London, W1D 1BS");
// { line1: "12 Oxford Street", city: "London",
// postalCode: "W1D 1BS", country: "GB", confidence: 0.8 }import { normalizeAddress } from "anyaddress";
normalizeAddress("123 main street, springfield, il 62704");
// "123 Main St, Springfield, IL 62704, US"import { detectCountry } from "anyaddress";
detectCountry("90210"); // "US"
detectCountry("K1A 0B1"); // "CA"
detectCountry("United Kingdom"); // "GB"parseAddress("4 Privet Drive, Little Whinging", { defaultCountry: "GB" });
parseAddress("...", { country: "US" }); // skip detection| Function | Returns | Description |
|---|---|---|
parseAddress(input, options?) |
ParsedAddress |
Parse free text into structured fields. Never throws. |
normalizeAddress(input, options?) |
string |
Parse + standardize casing/suffixes into one clean line. |
detectCountry(input) |
CountryCode | undefined |
Best-effort country from name or postal shape. |
formatAddress(parsed) |
string |
Render a ParsedAddress back to a single line. |
interface ParsedAddress {
raw: string;
line1?: string; // street number + name
line2?: string; // unit / apt / suite
city?: string;
region?: string; // state/province code when recognized
regionName?: string; // full state/province name
postalCode?: string;
country?: string; // "US" | "CA" | "GB" | "AU" | ...
confidence: number; // 0–1
}anyaddress |
parse-address |
node-postal (libpostal) |
|
|---|---|---|---|
| Pure JS, no native build | ✅ | ✅ | ❌ (C library) |
| Runs on edge / serverless | ✅ | ✅ | ❌ |
| International | ✅ (US/CA/GB/AU) | ❌ (US only) | ✅ (everywhere) |
| Maintained | ✅ | ❌ (2019) | ✅ |
| Install size | tiny | tiny | ~2 GB models |
| Accuracy on messy input | good | ok | best |
This is a pragmatic, rules-based parser, not a statistical NLP model. For the highest accuracy on arbitrary, messy, worldwide input, libpostal is still the gold standard. anyaddress targets the 80–90% common-format case with zero install pain — perfect for checkout forms, shipping, CRM dedupe, and edge functions. PRs to widen country coverage are very welcome.
Issues and PRs welcome — especially new country formats and test cases. Run npm test (Vitest) before submitting.
MIT © s4gor