A fast Go package for parsing Australian addresses according to Australia Post addressing standards, with reference data sourced from G-NAF (Geocoded National Address File).
- Fast: ~470,000 addresses/second (2.1μs per address)
- Accurate: 100% locality/state/postcode accuracy, 99%+ street parsing accuracy
- Complete: Supports all G-NAF street types, unit types, and level types
- Standards-compliant: Normalises to AusPost presentation format
This library handles single domestic destination address blocks with lines separated by \n. It normalises reasonably well-formed AU addresses to AusPost's standard format.
- Parses address components (locality, state, postcode, street details, unit/level, PO Box)
- Normalises addresses to AusPost presentation standards (uppercase, standard abbreviations)
- Validates syntactic correctness (valid state codes, 4-digit postcodes)
- Validate that an address actually exists or is deliverable
- Match against Australia Post's PAF (Postal Address File)
- Handle international addresses
- Guarantee AMAS compliance without external validation
For address existence validation, you'll need an external service like Australia Post's Address Validation API or an AMAS-certified solution.
go get github.com/ivanvanderbyl/auaddresspackage main
import (
"fmt"
"github.com/ivanvanderbyl/auaddress"
)
func main() {
addr, err := auaddress.Parse(`John Smith
123 Main Street
SYDNEY NSW 2000`)
if err != nil {
panic(err)
}
fmt.Printf("Street: %s %s %s\n", addr.StreetNumber, addr.StreetName, addr.StreetType)
// Output: Street: 123 MAIN ST
fmt.Printf("Locality: %s %s %s\n", addr.Locality, addr.State, addr.Postcode)
// Output: Locality: SYDNEY NSW 2000
}addr, _ := auaddress.Parse(`Jane Doe
Unit 5, 100 George Street
BRISBANE QLD 4000`)
fmt.Println(addr.Unit) // "UNIT 5"
fmt.Println(addr.StreetNumber) // "100"
fmt.Println(addr.StreetName) // "GEORGE"
fmt.Println(addr.StreetType) // "ST"addr, _ := auaddress.Parse(`Tenant
3A/45 High Street
MELBOURNE VIC 3000`)
fmt.Println(addr.Unit) // "3A"
fmt.Println(addr.StreetNumber) // "45"addr, _ := auaddress.Parse(`Company Pty Ltd
PO Box 1234
SYDNEY NSW 2000`)
fmt.Println(addr.IsPoBox) // true
fmt.Println(addr.PoBoxType) // "PO BOX"
fmt.Println(addr.PoBoxNumber) // "1234"addr, _ := auaddress.Parse(`john smith
123 main street
sydney nsw 2000`)
fmt.Println(addr.Format())
// Output:
// JOHN SMITH
// 123 MAIN ST
// SYDNEY NSW 2000By default, the parser is lenient and collects errors in the Errors slice while still returning a partial result. Use strict mode to fail immediately on validation errors:
parser := auaddress.NewParser(auaddress.WithStrict(true))
addr, err := parser.Parse("Invalid Address")
if err != nil {
// Handle error
}addr, _ := auaddress.Parse(input)
if addr.IsValid() {
// No parsing errors, has valid state and postcode
}
if addr.HasDeliveryPoint() {
// Has either street address or PO Box
}Benchmarked on Apple M4 Max:
BenchmarkGNAFParsing-16 575476 2138 ns/op 783 B/op 14 allocs/op
- ~470,000 addresses/second
- 2.1 microseconds per address
- 783 bytes allocated per parse
Tested against 5,000 real addresses from G-NAF November 2025:
| Metric | Accuracy |
|---|---|
| Locality/State/Postcode | 100% |
| Street Number | 99.8% |
| Street Name | 99.2% |
| Street Type | 99.4% |
| Unit Parsing | 99.3% |
type ParsedAddress struct {
RawLines []string // Original input lines
// PO Box / Special delivery
IsPoBox bool
PoBoxType string // "PO BOX", "GPO BOX", "LOCKED BAG", etc.
PoBoxNumber string
// Street address components
Unit string // "UNIT 5", "3A", etc.
Level string // "L 10", "FL 3", etc.
StreetNumber string // "123", "10-12", "45A"
StreetName string // "MAIN", "KING GEORGE"
StreetType string // "ST", "RD", "AV", etc.
StreetSuffix string // "N", "S", "E", "W", etc.
BuildingName string
// Locality line
Locality string // "SYDNEY", "ALICE SPRINGS"
State string // "NSW", "VIC", "QLD", "SA", "WA", "TAS", "ACT", "NT"
Postcode string // 4 digits
// Name/addressee lines
NameLines []string
// Parsing errors (in lenient mode)
Errors []error
}NSW, VIC, QLD, SA, WA, TAS, ACT, NT
Complete list from G-NAF including: STREET/ST, ROAD/RD, AVENUE/AV, DRIVE/DR, PLACE/PL, COURT/CT, CIRCUIT/CCT, CRESCENT/CR, TERRACE/TCE, PARADE/PDE, HIGHWAY/HWY, ESPLANADE/ESP, BOULEVARD/BVD, LANE, WAY, CLOSE/CL, and 200+ more.
UNIT, FLAT, APARTMENT/APT, VILLA, LOT, SHOP, SUITE, ROOM, OFFICE, FACTORY, WAREHOUSE, SHED, KIOSK, TOWNHOUSE, PENTHOUSE, STUDIO, and more.
LEVEL/L, FLOOR/FL, GROUND/G, BASEMENT/B, MEZZANINE/M, LOWER GROUND/LG, UPPER GROUND/UG, PODIUM, ROOFTOP, and more.
PO BOX, GPO BOX, LOCKED BAG, PRIVATE BAG, REPLY PAID, RMB, CMB, RSD, MS, CMA, CPA, CARE PO
The parser is validated against real addresses from G-NAF. To regenerate the test dataset:
- Download G-NAF from data.gov.au
- Extract to the repository root
- Run the generator:
go build ./cmd/gnaf-gen
./gnaf-gen -gnaf "g-naf_nov25_allstates_gda94_psv_1021/G-NAF/G-NAF NOVEMBER 2025/Standard" \
-output testdata/gnaf_addresses.json \
-count 10000The G-NAF dataset is excluded from git via .gitignore.
- Australia Post Addressing Guidelines
- Australia Post Addressing Standards
- AMAS Developer Guide
- G-NAF - Geocoded National Address File
MIT