303,525 datasets indexed1,419 publishers
Open Data IndexThe index of open data about the Netherlands
Sources›Education

DUO open education data

Every school and programme with its address, and per school location the number of pupils, school advice, end-of-primary test scores, exam results and forecasts. From primary school to university. DUO publishes it as downloads and as an API (56 datasets with 274 tables in the datastore on 16 October 2026).

EducationPopulationOpenAPIDownloadNetherlands · school location
Up to date · updated 10 hours ago · checked 17:23
duo.nl
Screenshot of duo.nl

Everything that's in it348

All datasets in DUO's catalogue, by subject as DUO groups them, with every file, fetched every night. Every table has its own page with the number of rows, the columns and the API call.

348in total
276tables
56datasets
19.7 mrows in total
154updated in the past 30 days

Arbeidsovereenkomst en cao5

Basisonderwijs74

Hoger onderwijs38

Inburgering3

Middelbaar beroepsonderwijs43

Speciaal onderwijs en leerproblemen55

Voortgezet onderwijs33

Zonder groep165

Pupils in primary education: 1.36 million in 2025/26, 10% less than in 1996/97

Pupils in primary education, 1996/97 – 2025/26, in million. The highest point was 2008/09 (1.55).

Source: DUO, Historische leerlingentellingen PO gemeente per jaar · opgehaald 25 oktober 2026 · selection: onderwijssoort BO; peildatum 1 oktoberOpen the table Single block

Vocational (MBO) students by field: most Health and social care (141,737 students), then Business and administration and Engineering and process industry

Vocational (MBO) students by field, October 2025, in students. Total: 475,113; the largest 12 of 17 categories are shown. Health and social care is 30% of the total. Enrolments on 1 October 2025 (provisional according to DUO). 567 cells with 1 to 4 students are suppressed and not counted.

Source: DUO, Mbo-studenten per sectorkamer en leerweg (studenten per sectorkamer, leerweg, niveau en woonprovincie) · opgehaald 25 oktober 2026 · selection: kolom JAAR_2025; per hoofdgroep naamOpen the table Single block

What you can build with it1

What can you do with it?4 ideas

Getting started

What advice do children get at your primary school?

Count the school advice per location per year (since 2010) and compare the school with others in the municipality.

Getting started

Shrinking and growing schools

Pupils per location are available from 2010 to 2025. Find schools that lost half their pupils in ten years.

Advanced

School advice next to the neighbourhood

Link locations by postcode or municipality number to income and education from the CBS key figures. Do children in poorer areas get lower advice?

Advanced

Where do the pupils come from?

The postcode4 file shows per location which postcode areas the pupils come from. That tells you how far parents travel for a school.

How to process it6 steps

  1. Find the dataset in the catalogue

    The catalogue is a CKAN portal. Search for a word and check which files (resources) belong to each dataset.

    https://onderwijsdata.duo.nl/api/3/action/package_search?q=advies&rows=5
  2. Query rows through the datastore

    Each CSV file is also in the datastore. With resource_id, filters and sort you fetch only what you need. This example: school advice for one school in 2024.

    https://onderwijsdata.duo.nl/api/3/action/datastore_search?resource_id=454c5dd4-6815-4b52-ae2f-b9eebc6afa6d&filters=%7B%22INSTELLINGSCODE%22%3A%2200AP%22%2C%22PEILJAAR%22%3A2024%7D
  3. Or download the whole file

    For a full analysis the CSV is easier. Some download links in the catalogue point to an internal server (beheer-ggm-ckan-prd…); replace the host with onderwijsdata.duo.nl.

    https://onderwijsdata.duo.nl/dataset/d6903313-8c64-4b12-b4ac-07e5655ef9f4/resource/454c5dd4-6815-4b52-ae2f-b9eebc6afa6d/download/brin6_advies.csv
  4. Join to addresses

    Pupil files only have the institution and location code. Name, address, postcode and municipality number are in the address files (for example all primary school locations).

    https://onderwijsdata.duo.nl/api/3/action/datastore_search?resource_id=dcc9c9a5-6d01-410b-967f-810557588ba4&limit=5
  5. Remove the small numbers

    A -1 means 1 to 4 pupils (suppressed). Don't count it as a number; use a lower and upper bound or leave it out.

  6. Accredited programmes in higher education

    The Overzicht Erkenningen ho (CC BY) gives per institution, location and programme the recognition, accreditation dates, study load, degree and status, current and historical: 74,173 rows on 16 October 2026. This dataset is only in DUO's catalogue, not on data.overheid.nl.

    https://onderwijsdata.duo.nl/api/3/action/datastore_search?resource_id=28a4d89b-c223-4dbc-8deb-9d02a533f215&limit=5

Interesting combinations

Similar sources

  • CBS StatLine

    CBS has education figures per municipality and nationally, not per school.

  • Scholen op de kaart not in the index yet

    School profiles for parents, partly based on DUO data. A website, not a dataset.

What to watch out for

  • Counts below 5 are suppressed

    The API then shows -1, some files show '<5'. For small schools that is a large share of the cells.

  • Not every dataset is current

    The register of schools and programmes (RIO) is refreshed daily, pupil counts once a year (reference date 1 October). Exam results per location in the API run to school year 2017 (as of 15 October 2026).

  • Codes without explanation in the API

    The ADVIES field is a number (for example 5, 7 or 11), not text. Look up the meaning at DUO before you count.

  • No SQL on the datastore

    datastore_search_sql returns 'no access'. Grouping and counting is up to you, after fetching.

  • Not everything is also on data.overheid.nl

    A few datasets are only in the DUO catalogue, such as Overzicht Erkenningen ho and Sectorale Ontwikkelpaden (which programmes belong to a development path and whether SLIM subsidy is possible). Sectorale Ontwikkelpaden has no licence in the catalogue (16 October 2026): licence not established.

APICKAN (Action API v3 + datastore) · read 16 Oct 2026

StandardCKAN (Action API v3 + datastore)docs
Access no key

No key or account needed tested

Size274

tables in the datastore (of 290 files in 56 datasets) tested

Formats

jsoncsv

Base URL

https://onderwijsdata.duo.nl/api/3/action

Endpoints 8

  • GET/package_listNames of all 56 datasets (e.g. adressen_bo, 03_voex-v1, historische-leerlingenaantallen-po).
  • GET/package_search?q=…&fq=…&rows=…Search the catalogue; rows=0 returns the count only. Also returns each dataset's resources (files) with id, format and datastore_active.
  • GET/package_show?id={naam}One dataset: description, licence, metadata_modified and the resources with their resource_id and download URL.
  • GET/resource_show?id={resource_id}One file: name, format, last_modified, download URL.
  • GET/group_listThe eight topic groups (basisonderwijs, voorgezet-onderwijs, hoger-onderwijs, inburgering …).
  • GET/group_show?id={groep}One group with title and description.
  • GET/datastore_search?resource_id={id}The rows of one table, with filters, full-text search, sorting, column choice and paging. The response also lists the columns with their type.
  • GET/dataset/{dataset-id}/resource/{resource_id}/download/{bestand}.csvThe whole file as CSV (path without /api/3/action, on https://onderwijsdata.duo.nl).

Filtering tested

No query language: equality filters as JSON in filters (value or list of values), plus full-text search with q. No greater-than or less-than; datastore_search_sql is disabled.

= (filters)IN (lijst in filters)q (vrij zoeken)

Parameters 10

resource_idRequired for datastore_search: the file id (from package_show).tested
filtersEquality filter per column as JSON, also with a list: {"PEILJAAR":[2023,2024]}. Column names exactly as in fields (sometimes with spaces: "BEVOEGD GEZAG NUMMER").tested
qFull-text search in all columns, or per column: {"PLAATSNAAM":"utrecht"} (word match, case-insensitive).tested
fieldsOnly these columns, comma-separated.tested
sortSorting, e.g. PEILJAAR desc.tested
limitNumber of rows; default 100 (CKAN). 40,000 was served fine; limit=0 returns only total and columns.tested
offsetPaging; the response has _links.next with the next page.tested
records_formatobjects (default), lists or csv (rows as one CSV string, no header).tested
include_totalfalse skips counting (faster on large tables).tested
q / fq / rows / start / sort (package_search)Solr search in the catalogue: fq=groups:basisonderwijs (24 datasets), sort=metadata_modified desc.tested

Fields in the datastore (selection: school advice and primary school addresses) 8

NameTypeMeaning
INSTELLINGSCODEtextBRIN-code van de school (4 tekens, bv. 00AP)
VESTIGINGSCODEtextVestiging: in leerlingbestanden 2 tekens (00), in adressenbestanden BRIN+2 (32JK00)
PEILJAARnumericJaar van de telling (peildatum 1 oktober)
ADVIESnumericSchooladvies als getalcode; de betekenis staat in de bestandsbeschrijving op duo.nl, niet in de API
AANTAL_LEERLINGENnumericAantal leerlingen; -1 = 1 tot 4 (afgeschermd)
GEMEENTENUMMERtextGemeentecode zonder GM, als tekst met voorloopnullen ("1699")
POSTCODEtextPostcode van de vestiging (adressenbestanden)
_idintRijnummer in de datastore

Limits and pitfalls

  • No key and no documented rate limit. Default 100 rows per call; a limit of 40,000 was served. Page with offset or _links.next. tested
  • Only some CKAN actions are open (package_list, package_search, package_show, resource_show, group_list, group_show, datastore_search). tested
  • Other CKAN actions (status_show, organization_list, tag_list, datastore_info, help_show) return HTTP 200 with the website's HTML, not a JSON error. Always check that the response is JSON. datastore_search_sql returns 400 "Action name not known". tested
  • distinct=true counts correctly (total 15 years in the school advice table) but returned only one row. For unique values, prefer a small column selection with a high limit. tested
  • Privacy: counts of 1 to 4 appear as -1 in the API (as <5 in some files). Don't add them up as numbers. tested
  • Nine download URLs in the catalogue point to an internal host (beheer-ggm-ckan-prd.apps.prd.duo.rijksapps.nl) that doesn't resolve outside DUO; replace the host with onderwijsdata.duo.nl. tested
  • Pupil files only have BRIN and branch code; name, address and municipality come from the address files (adressen_bo, adressen_vo …). Municipality number has no GM prefix: add GM and leading zeros to join with CBS. experience
  • Resource ids don't change with a new delivery; the dataset's metadata_modified and the resource's last_modified give freshness (addresses are refreshed daily). experience

Try it HTTP 200 · 694 ms · 16 Oct

https://onderwijsdata.duo.nl/api/3/action/datastore_search?resource_id=454c5dd4-6815-4b52-ae2f-b9eebc6afa6d&filters={"PEILJAAR"%3A2024}&sort=AANTAL_LEERLINGEN desc&limit=3
{
  "help": "https://onderwijsdata.duo.nl/api/3/action/help_show?name=datastore_search",
  "success": true,
  "result": {
    "filters": {
      "PEILJAAR": 2024
    },
    "include_total": true,
    "limit": 3,
    "records_format": "objects",
    "resource_id": "454c5dd4-6815-4b52-ae2f-b9eebc6afa6d",
    "sort": "AANTAL_LEERLINGEN desc",
    "total_estimation_threshold": null,
    "records": [
      {
        "_id": 104633,
        "INSTELLINGSCODE": "05VX",
        "VESTIGINGSCODE": "00",
        "TYPE_PO": "BO",
        "PEILJAAR": 2024,
        "ADVIES": 12,
        "AANTAL_LEERLINGEN": 234
      },
      {
        "_id": 492855,
        "INSTELLINGSCODE": "17ON",
        "VESTIGINGSCODE": "00",
        "TYPE_PO": "BO",
        "PEILJAAR": 2024,
        "ADVIES": 12,
        "AANTAL_LEERLINGEN": 78
      }
    ],
    "fields": [
      {
        "id": "_id",
        "type": "int"
      },
      {
        "id": "INSTELLINGSCODE",

Shortened response, saved at harvest time. Click the URL for the real, current response.

Read from CKAN Action API (platform documentation) · CKAN datastore_search: filters, q, sort, fields, distinct · DUO: explanation per topic and file descriptions. Labels: from the description stated in what the api itself publishes. tested from our own small call. platform applies to every api on this platform, per its documentation. experience learned while building open data index.

How to fetch it

curl -G "https://onderwijsdata.duo.nl/api/3/action/datastore_search" --data-urlencode "resource_id=454c5dd4-6815-4b52-ae2f-b9eebc6afa6d" --data-urlencode "filters={\"PEILJAAR\":2024}" --data-urlencode "limit=5"

More from DUO in our index

461 datasets in DUO open onderwijsdata, data.overheid.nl. These changed most recently.

All about DUO

More in this topic

See how this page is built
bron: duo-onderwijsdata
blokken: []
secties:
  - ideeen
  - verwerken
  - koppelingen
  - vergelijkbaar
  - beperkingen
  - code
cache:
  tag: bron:duo-onderwijsdata
  ververs: na statuscheck, als de bron nieuwer is
statuscheck:
  methode: "CKAN-catalogus: nieuwste gewijzigde dataset (metadata_modified)"
  verwacht: dagelijks

Source: content/bronnen/duo-onderwijsdata.yaml · Markdown