Part of a Data Solution
- Explore →
Postal Codes Solution
Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.
Premium
You're viewing a free sample
Get the complete dataset — all rows and files — delivered instantly after checkout, with lifetime access to the latest version.
- Secure checkout via Stripe
- Instant download after payment
- Lifetime access to the latest version
- CC0 1.0 Universal (public domain) — LJPc-solutions postal codes and coordinates license
API Access
Access dataset files directly from scripts, code, or AI agents.
Browse dataset files
API Access
Access dataset files directly from scripts, code, or AI agents.
Each file has a stable URL (r-link) that you can use directly in scripts, apps, or AI agents. These URLs are permanent and safe to hardcode.
Start with these files — they give you everything you need to understand and access the dataset.
- 1. Fetch datapackage.yaml to inspect schema and resources
- 2. Download data resources listed in datapackage.yaml
- 3. Read README.md for full context
Data Files
postal-codes-nl-sample
| Field | Type | Description | Constraints | Title |
|---|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 country code — always NL | { "pattern": "^NL$", "required": true } | Country Code |
| postal_code | string | Dutch postal code, format 'NNNNAA' (4 digits + 2 letters) | { "pattern": "^[0-9]{4}[A-Z]{2}$", "required": true } | Postal Code |
| place_name | string | Locality (woonplaats) served by the postal code | Place Name | |
| admin_name1 | string | Province (provincie) | Administrative Name 1 | |
| admin_code1 | string | ISO 3166-2:NL province code, prefix stripped (e.g. NH, ZH) | Administrative Code 1 | |
| admin_name2 | string | Municipality (gemeente) | Administrative Name 2 | |
| admin_code2 | string | Reserved — no municipality code in the source; always blank | Administrative Code 2 | |
| admin_name3 | string | Locality (woonplaats) — the third administrative tier | Administrative Name 3 | |
| admin_code3 | string | Reserved — always blank | Administrative Code 3 | |
| latitude | number | Latitude, decimal degrees (WGS84) | Latitude | |
| longitude | number | Longitude, decimal degrees (WGS84) | Longitude | |
| accuracy | string | Coordinate precision tier — BLOCK (postcode-block level) | Accuracy | |
| alternative_city_name | string | Not available for this dataset — always blank | Alternative City Name |
Download
Download sample CSVAbout
- Last updated
- 11 October 2026
- Total rows
- 100
- Format
- CSV
- File size
- 7.99 kB
About this dataset
Netherlands (NL): migration notes
Internal record of the P5 migration from the staged-export converter to the producer: the discrepancies found, their causes, and who decided what. This is a dated record (2026-10-11), so the numbers are as of the migration and not kept current. It is not shipped in the zip.
- Issue: datopian/postal-codes#41
- Commit: the producer commit on this branch. It also adds
zstandardtorequirements-producers.txt(the address file is zstd-compressed) - Parity verdict:
unexplained(gate: blocked), accepted under the owner's under-1% rule: 0.79% of live rows are affected (157 gone, 3,526 with a shifted coordinate), all traced to the source file having been updated - Producer:
custom, refresh disabled
What made the live file, verified
The old convert_from_fedex.py read a staged copy of the prototype's Netherlands.csv, which no longer exists. That delivery is the output of the fedex-agents-prototype countries/NLD build: scrape_postal.py (Phase 1: dedupe the LJPc address file), scrape_admin.py (CBS), combine_phase2.py (join), then a QA pass that ordered the rows by province and appended two 00000 backfill rows. The converter then dropped those two rows and mapped the columns.
Verified on 2026-10-11:
- The old converter on the staged export reproduces the live
nl.csvbyte for byte. - This producer's join and rendering, fed the prototype's saved Phase 1 and admin files (
postal_raw.csv,admin.csv), reproduces the livenl.csv: same 467,628 rows, same order, the same bytes apart from CRLF. - Differential check on fresh inputs. The prototype's own three scripts and this producer were run on the same downloaded files (the LJPc file of 2026-10-10 and today's CBS tables). Phase 1: 467,747 unique rows, identical and in the same order. Admin: 2,501 records, identical. Phase 2: 467,729 rows, identical and in the same order. So none of the parity differences below come from the port.
Sources
| Input | URL | Notes |
|---|---|---|
| LJPc address file | https://raw.githubusercontent.com/LJPc-solutions/Nederlandse-adressen-en-postcodes/main/Nederland.csv.zst | CC0 1.0. ~10 million address rows, 75 MB compressed. Updated on 2026-10-10 ("Periodieke update") and the repository shows a single commit for it, so the August snapshot behind the live file cannot be fetched |
| CBS Woonplaatsen dimension | https://opendata.cbs.nl/ODataApi/OData/86097NED/Woonplaatsen | CC BY 4.0 |
| CBS TypedDataSet | https://opendata.cbs.nl/ODataApi/OData/86097NED/TypedDataSet | CC BY 4.0. Each province, municipality and locality name in the output comes from here |
The prototype also fetched Wikipedia's municipality list, but only to print a cross-check; it never changed the data, so it is not an input here.
Parity against the live zip (2026-10-11)
| Rows | Share of live | |
|---|---|---|
| live | 467,628 | |
| fresh | 467,729 | |
| only in live | 157 | 0.034% |
| only in fresh | 258 | 0.055% |
| in both, with a changed coordinate | 3,526 | 0.754% |
| changed cells | 6,790 (latitude 3,372, longitude 3,418) | 0.11% of all cells |
Names, provinces and municipalities do not change on any row present in both files; only coordinates do. 446 of the cell changes are rounding-level (parity class coordinate_precision), 6,344 are other coordinate changes.
Cause: the LJPc file was updated since the live build (upstream drift). Phase 1 keeps the first address in file order for each (postcode, woonplaats, gemeente, provincie), so when addresses are added, removed or re-geocoded, that first address (and its coordinate) can change, and a few combinations appear or disappear. CBS also gained one woonplaats since the saved admin file (2,501 against 2,500). This is the "larger parity diff" plan decision D1 anticipated for a producer rebuilt from the original source.
Decisions
| Decision | By | Basis |
|---|---|---|
| Go back to the original sources and port the prototype's three scripts into one producer | Plan D1; owner, 2026-10-11 ("work on those that are available") | The staged export is gone; both sources answer |
| Accept 157 rows gone, 258 new, 3,526 shifted coordinates (0.79% of live rows) | Owner, 2026-10-11 ("if they differ by less than 1%, then ok"); standing rule for traced upstream drift | Differential check above |
Do not produce the two 00000 backfill rows | Agent: a faithful port of the conversion | The converter always dropped them (not postal codes); they were also the only CC BY dependency in the old data path, and ATTRIBUTION now credits CBS for the names anyway |
Drop additionalInfo ("Postal station: …", 8 rows) | Agent: a faithful port | It had no column in the 13-column format; the old converter dropped it too |
| Keep the stable sort by province code | Agent: a faithful port | The prototype's QA ordered the final file this way; canonical_order then sorts only inside a shared postal code |
zstandard (not the zstd command) to read the file; imported lazily | Agent | CI's test job installs requirements.txt only; the one test that needs it is skipped there |
| No exact row-count assert; unresolved postal rows under 1% | P5 rule | The old documents expected "~470,000" |
| LF line endings; README and ATTRIBUTION kept from the repo | Standing rule / agent | The repo copies were corrected in #38 and name both sources |
Transforms carried over
- Phase 1: first occurrence of each (postcode, woonplaats, gemeente, provincie); postcode must match
[1-9]\d{3}[A-Z]{2}; coordinates rounded to 5 decimals. - Join: exact (woonplaats + gemeente); the woonplaats alone, or the most similar gemeente when several share it; fuzzy woonplaats (ratio at least 85); else the parent gemeente. Duplicates on (postal code, locality) keep the row whose gemeente is listed first for that locality.
place_nameandadmin_name3are both the woonplaats; accuracy isBLOCK; no codes below the province.
Open questions
- R2 is untouched. The public sample in R2 is not the first 100 rows of this file's current order; publishing replaces it.
Provenance
Written 2026-10-11 from the saved prototype files, the differential run described above, scripts/parity.py nl (reads the live zip, writes nothing) and the Frictionless validation of the built zip.