Framework-agnostic TypeScript library for Philippine address lookup, ZIP autofill, and hierarchical region → province → municipality → barangay selection.
- ZIP Autofill — Resolve a 4-digit ZIP code into region, province, municipality, and barangays.
- Cascading Selection — Full PSGC hierarchy:
getRegions → getProvinces → getMunicipalities → getBarangays - Full Path Resolution — Resolve any PSGC code upward through the hierarchy with
getFullPath. - Free-Text Search — Search across all address levels with optional fuzzy matching and parent scoping.
- Alias Resolution — Resolve region nicknames and abbreviations (e.g.
"NCR","CALABARZON") to PSGC codes. - Validation — Verify that address codes exist and form a consistent hierarchy.
- Zero Runtime Dependencies — No API calls. Works offline and at the edge.
- TypeScript First — Fully typed API with
.d.tssupport (CJS + ESM). - Official PSGC Data — Based on PSA PSGC Q4 2025. Covers 17 regions, 80 provinces, 42,000+ barangays.
npm install @bzync/ph-address-intelyarn add @bzync/ph-address-intel
pnpm add @bzync/ph-address-intel
bun add @bzync/ph-address-intelimport {
lookupByZip,
getRegions,
getProvinces,
getMunicipalities,
getBarangays,
getFullPath,
search,
resolveAlias,
validate,
} from '@bzync/ph-address-intel'
// ZIP autofill
const result = lookupByZip('4322')
// Hierarchical selection
const regions = getRegions()
const provinces = getProvinces('040000000')
const municipalities = getMunicipalities('045600000')
const barangays = getBarangays('045645000')
// Full path from any PSGC code
const path = getFullPath('045645001') // barangay → full chain
// Scoped search (municipalities within CALABARZON only)
const hits = search('San Jose', { types: ['municipality'], parentCode: '040000000' })
// Alias resolution
const ncr = resolveAlias('NCR')
// Validation
const check = validate({ regionCode: '040000000', provinceCode: '045600000' })Resolves a 4-digit ZIP code to the full address hierarchy.
const result = lookupByZip('4322')
if (result) {
console.log(result.region.name) // "Region IV-A (CALABARZON)"
console.log(result.province?.name) // "Quezon"
console.log(result.municipality.name) // "Sariaya"
console.log(result.barangays.length) // number of barangays
}getRegions(): Region[]
getProvinces(regionCode: string): Province[]
getMunicipalities(provinceCode: string): Municipality[]
getBarangays(municipalityCode: string): Barangay[]Returns all items at each level. Pass the parent PSGC code to get children.
getRegion(code: string): Region | undefined
getProvince(code: string): Province | undefined
getMunicipality(code: string): Municipality | undefined
getBarangay(code: string): Barangay | undefinedO(1) lookups by PSGC code.
Resolves any PSGC code upward through the hierarchy and returns the complete address chain.
// From a barangay code
const path = getFullPath('045645001')
// → { region, province, municipality, barangay }
// From a municipality code
const path = getFullPath('045645000')
// → { region, province, municipality, barangay: null }
// NCR municipality (no province)
const path = getFullPath('133900000')
// → { region, province: null, municipality, barangay: null }
// Unknown code
getFullPath('999999999') // → nullAccepts codes at any level — region, province, municipality, or barangay. Levels below the given code are null.
Searches across all address levels. Supports substring matching (default) and fuzzy matching, with optional scoping to a parent region, province, or municipality.
// Substring search
search('Manila')
// Fuzzy search with options
search('Mandaluyong', { fuzzy: true, limit: 5, types: ['municipality'] })
// Scoped to a region (useful for cascading dropdowns)
search('San Jose', { types: ['municipality'], parentCode: '040000000' })
// Scoped to a municipality
search('Antipolo', { types: ['barangay'], parentCode: '045645000' })SearchOptions
| Option | Type | Default | Description |
|---|---|---|---|
fuzzy |
boolean |
false |
Enable Dice's bigram fuzzy matching |
limit |
number |
— | Max results to return |
types |
Array<'region' | 'province' | 'municipality' | 'barangay'> |
all | Restrict search to specific levels |
parentCode |
string |
— | Scope results to children of a region, province, or municipality |
Results are sorted by score (descending) when fuzzy: true. When parentCode is set, regions are excluded from results (the parent context is already known).
Resolves a common region nickname, abbreviation, or number to a SearchResult. Returns null if not recognized.
resolveAlias('NCR') // → { type: 'region', code: '130000000', name: '...' }
resolveAlias('Region IV-A') // → { type: 'region', code: '040000000', name: '...' }
resolveAlias('BARMM') // → { type: 'region', code: '150000000', name: '...' }
resolveAlias('unknown') // → nullRecognized aliases include region numbers (Region 1–13), Roman numerals (Region I–XIII), official names, and common shorthands (NCR, CAR, CALABARZON, MIMAROPA, CARAGA, etc.).
Validates that the provided PSGC codes exist and form a consistent hierarchy. Only fields that are provided are validated — partial inputs are fine.
validate({ regionCode: '040000000', provinceCode: '045600000' })
// → { valid: true, errors: [] }
validate({ regionCode: '040000000', provinceCode: '010100000' })
// → { valid: false, errors: ['Province "Ilocos Norte" does not belong to region "040000000"'] }interface Region {
code: string
name: string
}
interface Province {
code: string
name: string
regionCode: string
}
interface Municipality {
code: string
name: string
regionCode: string
provinceCode: string | null
isCity: boolean
zipCodes: string[]
}
interface Barangay {
code: string
name: string
municipalityCode: string
}
interface ZipLookupResult {
zip: string
region: Region
province: Province | null
municipality: Municipality
barangays: Barangay[]
}
interface SearchResult {
type: 'region' | 'province' | 'municipality' | 'barangay'
code: string
name: string
score?: number
regionCode?: string
provinceCode?: string | null
municipalityCode?: string
}
interface FullPath {
region: Region
province: Province | null
municipality: Municipality | null
barangay: Barangay | null
}
interface SearchOptions {
fuzzy?: boolean
limit?: number
types?: Array<'region' | 'province' | 'municipality' | 'barangay'>
parentCode?: string
}
interface ValidationInput {
regionCode?: string
provinceCode?: string
municipalityCode?: string
barangayCode?: string
}
interface ValidationResult {
valid: boolean
errors: string[]
}RRPPMMMBBB
| Part | Meaning |
|---|---|
| RR | Region |
| PP | Province |
| MMM | Municipality |
| BBB | Barangay |
Example:
040000000 → Region IV-A (CALABARZON)
045600000 → Quezon
045645000 → Sariaya
045645001 → Barangay Antipolo
- NCR has no provinces —
provinceisnullin ZIP lookup results. - ZIP dataset contains ~958 mappings; some barangays share ZIP codes.
- BARMM barangay data may be incomplete (PSGC limitation).
MIT License © 2026
Star the repo if this helped you: https://github.com/bzync/ph-address-intel