Welcome to the BAG: The Dutch Building and Addresses database

Recently, I wrote a small open source tool to make the official Dutch national address & building database more accessible. More about the tool below, but first an introduction.

Last data update: 2024-04-10

If all you need is an up to date CSV file of all Dutch addresses, their zipcodes and coordinates, scroll down to the end. If all you need is a web service, try https://berthub.eu/pcode/2513AA/14. For more details (including a live demo), do read on.

The BAG

For some reason, The Netherlands (through Het Kadaster) keeps obsessively good records of buildings, dwellings and addresses. Everything here has a full address, postal code and house number.

As an example, this is the “Hall of Knights” (dating from 1288):


Source: Wikipedia user Zairon

Check the gray arrow: this is Binnenhof 14, 2513 AA, ’s-Gravenhage. We also give the fixed location of floating objects and mobile homes postal codes and addresses.

All this data is kept in the Basisregistratie Adressen en Gebouwen, lovingly known as the BAG: Basic Registration of Building and Addresses. It is not basic, however.

The BAG has the location and shapes (!) of all buildings, knows about all ‘places of dwelling’ (including offices, shops, houses, flats etc), and documents in which buildings these dwellings can be found. Each of these places of dwelling can also have one or more addresses, and postal codes. Buildings also include things like (brick) sheds. I didn’t even know it, but someone made an entry for the bicycle shed we built a few years ago, for example.

If your thing is not in the BAG, you are going to have a very hard time getting anything done in The Netherlands. And I speak from experience, having lived and worked in places there weren’t registered quite correctly. Your packages and cable installations just bounce off the system.

These days, if you find something wrong in the database, you can go to the BAG Viewer and press the button “Fout Melden” (“Report Error”) and your report will get forwarded to the right city or part of government and they will actually get on it. I reported a small error last week, and it got resolved within 24 hours, so it really works.

It truly is quite amazing. And all this data is completely free and publicly available!

You can query the official database over an API for free (this ‘sparql’ also looks cool), but there are limitations on that, and also no SLA. If you want to download the whole thing, there are three options:

So the choices are “relatively expensive and hassle”, incomplete data or hard to use data. Also, all documentation is exclusively in Dutch.

Note that there are many more interesting databases. You can find them on https://www.pdok.nl/datasets. Also, there is existing professional GIS tooling that can do BAG conversions with quite some work and hassle, including: NLExtract, GDAL. These tools then offer far more powerful capabilities beyond a simple conversion.

29th of June update, Jan Derk also wrote a tool (in Python) that converts the BAG XML to SQLite!

Converting the BAG XML

Now, many people may dislike XML. And it is indeed easy to have strong feelings about 83 gigabytes of files coming out of a 3 GB .ZIP. Intrinsically however, there is not a lot wrong with the format: the data we need is in there.

It is however not that accessible if you aren’t an ‘XML native’. And even if you are, XML is not a database.

Many people will only need an extract, perhaps a CSV, from the BAG. Other folks might want to query it for research, statistics or even business uses. Now, I’m not the first one to notice that it might be useful to convert the BAG to a real database. Bart Noordervliet wrote a generic tool that can map XML objects to PostgreSQL, including the BAG.

Bagconv

Recently I wrote a dedicated open source tool called bagconv for this purpose which also papers over some semantics of the BAG that are easy to get wrong.

For example, within the BAG every street lies within in a city. By default, places of dwelling on that street therefore also reside in that city. However, there are many exceptions where there is an override for a house that belongs to another city than the street it lies on. To prevent you from having to do that check, which you might forget, bagconv fills out an explicit field that always has the right city for an address. But do read below what a ‘city’ is in this context.

Bagconv will take the XML files and convert them into an SQLite database. This database contains all BAG objects, and also their N:M relations: a place of dwelling can span multiple buildings, but a building might also contain multiple dwelling places.

In addition, bagconv comes with a set of SQLite views that make common queries a lot easier. Dutch addresses are described completely by a ZIP code and a house number for example:

sqlite> select * from alllabel where postcode='7311KZ' and huisnummer=110 
        and woonplaats='Apeldoorn';
        straat = Hofstraat
    huisnummer = 110
    huisletter = 
huistoevoeging = 
    woonplaats = Apeldoorn
      postcode = 7311KZ
             x = 194315.783
             y = 469449.074
           lon = 5.96244253360916
           lat = 52.2117344207437
   oppervlakte = 8870
gebruiksdoelen = ["kantoorfunctie"]
      bouwjaar = 1985
    num_status = Naamgeving uitgegeven
    vbo_status = Verblijfsobject in gebruik
      vbo_type = vbo
        num_id = 0200200000007079
        vbo_id = 0200010000090244
        opr_id = 0200300022471548
        pnd_id = 0200100000001088

This is the HQ of the Dutch agency in charge of the BAG database. If we want to get the shape of their building, that goes like this:

sqlite> select geo from alllabel, pnds where postcode='7311KZ' and huisnummer=110 
  and pnds.id=pnd_id;
  geo = 194305.556 469481.503 0.0 194293.842 469472.735 0.0 194299.704 469458.128 0.0 
  194308.96 469435.067 0.0 194314.846 469437.415 0.0 194313.03 469441.967 0.0 
  194315.389 469442.923 0.0 194318.6 469438.659 0.0 194322.608 469441.677 0.0 
  194330.846 469447.881 0.0 194327.825 469451.891 0.0 194320.342 469461.906 0.0 
  194307.626 469478.806 0.0 194306.163 469480.712 0.0 194305.556 469481.503 0.0

These are coordinates based on the Dutch national grid, more about which below.

Full details on what bagconv does can be found on the GitHub page.

NOTE THAT BAGCONV IS STILL VERY NEW SOFTWARE! I’ve compared the output to commercial offerings, and this has led to some bug fixes. There are no important discrepancies, only some very minor differences in interpretation. Being open source however, this software comes with no guarantee.

Pre-built CSV files

The Dutch government releases an updated extract of the BAG on the 8th of every month.

As a service, I convert each release to two CSV files that probably cover a lot of needs already.

I provide some brief guidance below on what the fields mean, but the Final Word is in the official manual which is sadly only available in Dutch.

  • pcodes.csv (55MB .zip), containing all physical addresses, including ones that haven’t (yet) been assigned a postcode:
    • straat: street name
    • huisnummer: house number (only digits)
    • huisletter: house letter (a single character, optional)
    • huistoevoeging: house suffix (up to 4 characters or digits, optional)
    • woonplaats: a slightly tricky term to translate. “Town or city”, but this is a geographical and not a political name. So for example, I live in Nootdorp which originally had its own local government (city council), but this is now part of the municipality Pijnacker-Nootdorp. For my house, ‘woonplaats’ is Nootdorp, and this is also what people here will typically answer if you ask them which town they live in. Note that some cities and towns have multiple names here, but the database will only list one. The Hague is for example known as ’s-Gravenhage in the database, but many people call it Den Haag.
    • postcode: four digits, no space, and then two characters. Officially a postcode has a space in it, but it seems silly to store millions of spaces.
    • oppervlakte: area of the place of dwelling in square meters
    • gebruiksdoelen: an indication of what this address is used for. This in turn is often used to figure out if you could deliver a package somewhere during the weekend. ‘woonfunctie’ is a house, ‘winkelfunctie’ a shop, ‘sportfunctie’ you can guess. Intriguingly, 135 addresses are classified as prisons. In recent versions of the software this is an array of functions.
  • pcodes-geo.csv (263MB .zip):

You can download the smaller file from berthub.eu/bagconv/pcodes.zip - and add ‘-geo’ behind ‘pcodes’ to get the (far) larger file with geographical formats. Please don’t download these files just for fun, they are reasonably large (55 and 263MB respectively).

As a webservice

If you run bagserv 2345 locally, you can send it the following queries:

  • http://0.0.0.0:2345/7311KZ/110 - all addresses with postcode 7311KZ and house number 110
  • http://0.0.0.0:2345/7311KZ/110/A - all addresses with postcode 7311KZ and house number 110 and house letter A
  • http://0.0.0.0:2345/7311KZ - all addresses with postcode 7311KZ
  • http://0.0.0.0:2345/52.2117344207437/5.96244253360916 - the address closest to 52.2117344207437N, 5.96244253360916E (WGS84)

The answer in all cases is straightforward JSON with one or more addresses in there:

[
  {
    "bouwjaar": "1985",
    "gebruiksdoelen": ["kantoorfunctie"],
    "huisletter": "",
    "huisnummer": "110",
    "huistoevoeging": "",
    "lat": "52.2117344207437",
    "lon": "5.96244253360916",
    "num_status": "Naamgeving uitgegeven",
    "oppervlakte": "8870",
    "straat": "Hofstraat",
    "vbo_status": "Verblijfsobject in gebruik",
    "woonplaats": "Apeldoorn"
  }
]

Often, the testing instance on https://berthub.eu/pcode/ will be active. Send it queries like https://berthub.eu/pcode/7311KZ/110.

Live demo

Give it a try on a Dutch address:


Finally

The actual open source software and more details can be found on GitHub.

If you find any problems, or have additional requirements, please do open a ticket there.