# Postcodes, municipalities and regions for dropdowns

> Fetch the full lists of postcodes, municipalities and regions, cache them properly and avoid the usual mistakes with municipality codes.
>
> https://danadresse.dk/en/guides/postnumre-og-kommuner · verified 2026-11-02
A dropdown of municipalities, a filter by region or a postcode field that fills in the town name: the lists rarely change, so fetch them once and keep them. This guide shows the three endpoints and how to cache them.

## Regions

`GET /regioner` returns the five regions in one list:

```bash id=regioner-curl run=live expect="nuts2"
curl -s "https://api.danadresse.dk/regioner" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

Each region has `kode` (1081-1085), `navn` and `nuts2`. The list is sorted by code.

## Municipalities

`GET /kommuner` returns the municipalities sorted by name. The whole list comes in one call:

```python id=kommuner-python run=live expect="kommuner"
import os
import requests

r = requests.get(
    "https://api.danadresse.dk/kommuner",
    params={"per_side": 500},
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=15,
)
r.raise_for_status()
kommuner = r.json()

options = [(k["kode"], k["navn"]) for k in kommuner if not k["udenforkommuneinddeling"]]
print(f"{len(options)} kommuner til dropdown")
for kode, navn in options[:5]:
    print(f'  <option value="{kode}">{navn}</option>')
```

| Field | Content |
|---|---|
| `kode` | Four digits as text, e.g. `0101` |
| `navn` | The municipality's name |
| `regionskode`, `regionsnavn` | The region the municipality is in |
| `region` | The same as an object with `href` |
| `udenforkommuneinddeling` | `true` only for Christiansø (`0411`), which belongs to no municipality |

The list holds the 98 municipalities plus Christiansø. Filter Christiansø out with `udenforkommuneinddeling` if you only want real municipalities. `GET /kommuner?regionskode=1084` gives the municipalities in one region.

## Postcodes

There are about 1,100 postcodes, and `GET /postnumre` returns all of them in one response, sorted by number, like DAWA. If you would rather fetch them in chunks, use `side` and `per_side` (up to 1000).

```python id=postnumre-python run=syntax
import json
import os
import requests

s = requests.Session()
s.headers["X-Api-Key"] = os.environ["DANADRESSE_API_KEY"]

r = s.get("https://api.danadresse.dk/postnumre", timeout=60)   # the whole list
r.raise_for_status()
postnumre = [{"nr": p["nr"], "navn": p["navn"],
              "kommuner": [k["kode"] for k in p["kommuner"]]} for p in r.json()]

with open("postnumre.json", "w", encoding="utf-8") as f:
    json.dump(postnumre, f, ensure_ascii=False)
print(len(postnumre), "postcodes saved")
```

| Field | Content |
|---|---|
| `nr` | Four digits as text |
| `navn` | The postal district's name, e.g. `København V` |
| `kommuner` | The municipalities the postcode covers, as `{href, kode, navn}` |
| `stormodtager` | `false` for geographic postcodes. The list only shows those unless you add `stormodtagere=true`. See [Large-recipient postcodes](/en/guides/stormodtagere) |
| `dagi_id` | The DAGI id of the postcode area |

A postcode can cover several municipalities. So never derive the municipality from the postcode. Use the address (see [Find the municipality, region and parish of an address](/en/guides/kommune-sogn-politikreds)).

## A postcode field that fills in the town

For a single field you do not need the whole list. `GET /postnumre/{nr}` looks up one postcode, and `GET /postnumre/autocomplete?q=` suggests postcodes from the start of the number or the name:

```bash id=postnr-autocomplete run=live expect="tekst"
curl -s "https://api.danadresse.dk/postnumre/autocomplete?q=Hel&per_side=5" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

The response is a list of `{"tekst": "2900 Hellerup", "postnummer": {…}}`. `GET /kommuner/autocomplete?q=` works the same way for municipalities.

## Cache the lists

Postcodes and municipalities change a few times a year. Fetch them once a day on the server, store them in a file, Redis or your database, and serve the dropdown from there. That saves calls and makes the form faster.

The responses from `/kommuner`, `/regioner` and `/postnumre` carry `Cache-Control: private, max-age=86400, stale-while-revalidate=604800`. A browser therefore caches them for a day. Responses under 256 KB also carry an `ETag`: if you send `If-None-Match` with it, the API answers `304 Not Modified` without a body when the list has not changed. The full postcode list is larger and has no `ETag`.

```js id=cache-node run=syntax
import { readFile, writeFile } from "node:fs/promises";

const FIL = "./kommuner.json";
const MAKS_ALDER_MS = 24 * 60 * 60 * 1000;

export async function kommuner() {
  try {
    const cache = JSON.parse(await readFile(FIL, "utf8"));
    if (Date.now() - cache.hentet < MAKS_ALDER_MS) return cache.data;
  } catch {
    // no cache yet
  }
  try {
    const res = await fetch("https://api.danadresse.dk/kommuner?per_side=500", {
      headers: { "X-Api-Key": process.env.DANADRESSE_API_KEY },
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const data = (await res.json()).map((k) => ({ kode: k.kode, navn: k.navn }));
    await writeFile(FIL, JSON.stringify({ hentet: Date.now(), data }));
    return data;
  } catch (err) {
    // The API does not answer: use the old cache if there is one
    const gammel = JSON.parse(await readFile(FIL, "utf8").catch(() => "null"));
    if (gammel) return gammel.data;
    throw err;
  }
}
```

If you fetch the list from the browser, use a browser key locked to your domain and keep the result in `localStorage` with a timestamp.

## Municipality codes: the usual mistakes

- **Leading zero.** The code is `0101`, not `101`. The API always returns four digits, but Excel and many JSON parsers turn the code into a number if you let them. Store it as text.
- **Input without the zero works.** Filters and lookups accept the code without the zero and pad it: `kommunekode=101`, `kommunekode=101|147` and `/kommuner/101` give the same as `0101`. The same goes for postcodes such as `/postnumre/800`.
- **A region code is not a municipality code.** Regions have the codes 1081-1085. Municipality codes run from `0101` to `0860`.

## Next steps

- [Find the municipality, region and parish of an address](/en/guides/kommune-sogn-politikreds)
- [Large-recipient postcodes in forms](/en/guides/stormodtagere)
- [Caching](/en/guides/caching)
