Postal Codes Dataset for Netherlands, NL

754
Updated:
Files:1
Size:37.6 MB
Rows:467,729
Formats:csv

Postal Codes Dataset for Netherlands, NL including name of the city, town, or place, various administrative divisions and alternative city names.

Part of a Data Solution

  • Postal Codes Solution

    Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.

    Explore →

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
20% off
$99.90$79.92
one-time payment

API Access

Access dataset files directly from scripts, code, or AI agents.

Browse dataset files
Dataset Files

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.

/logistics/postal-codes-nl/
https://datahub.io/logistics/postal-codes-nl/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-nl/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-nl/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-nl/_r/-/README.md
https://datahub.io/logistics/postal-codes-nl/_r/-/datapackage.yaml
Key Files

Start with these files — they give you everything you need to understand and access the dataset.

datapackage.yaml— metadata & schema
https://datahub.io/logistics/postal-codes-nl/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-nl/_r/-/README.md
Typical Usage
  1. 1. Fetch datapackage.yaml to inspect schema and resources
  2. 2. Download data resources listed in datapackage.yaml
  3. 3. Read README.md for full context

Data Files

postal-codes-nl-sample


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 zstandard to requirements-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.csv byte 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 live nl.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

InputURLNotes
LJPc address filehttps://raw.githubusercontent.com/LJPc-solutions/Nederlandse-adressen-en-postcodes/main/Nederland.csv.zstCC0 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 dimensionhttps://opendata.cbs.nl/ODataApi/OData/86097NED/WoonplaatsenCC BY 4.0
CBS TypedDataSethttps://opendata.cbs.nl/ODataApi/OData/86097NED/TypedDataSetCC 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)

RowsShare of live
live467,628
fresh467,729
only in live1570.034%
only in fresh2580.055%
in both, with a changed coordinate3,5260.754%
changed cells6,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

DecisionByBasis
Go back to the original sources and port the prototype's three scripts into one producerPlan 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 driftDifferential check above
Do not produce the two 00000 backfill rowsAgent: a faithful port of the conversionThe 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 portIt had no column in the 13-column format; the old converter dropped it too
Keep the stable sort by province codeAgent: a faithful portThe 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 lazilyAgentCI'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 ruleThe old documents expected "~470,000"
LF line endings; README and ATTRIBUTION kept from the repoStanding rule / agentThe 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_name and admin_name3 are both the woonplaats; accuracy is BLOCK; 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.