How the Denmark løn efter skat calculator is verified
Inputs
| Input | Field | Type |
|---|---|---|
| Bruttoløn / år (DKK) | grossAnnual | number |
| Kommune | kommune | string |
| Kommuneskat hvis « Anden » (f.eks. 0.251) | customMunicipalRate | number |
The formula
Each derived value below is computed by the Valem engine from the expression shown, in this order. Nothing else runs — there is no hidden code path.
| Derived value | Field | Formula (JSONata) |
|---|---|---|
| Kommuneskat | municipalRate | ($s := kommune; $s = 'gennemsnit' ? $const.rateGennemsnit : $s = 'koebenhavn' ? $const.rateKoebenhavn : $s = 'hoejeste' ? $const.rateHoejeste : customMunicipalRate) |
| Atp | atp | $round(grossAnnual > 0 ? $const.atpAnnual : 0, 2) |
| AM-bidrag (8%) | amBidrag | ($b := grossAnnual - atp; $round(($b > 0 ? $b : 0) * $const.amRate, 2)) |
| After Am | afterAm | ($a := grossAnnual - amBidrag - atp; $round($a > 0 ? $a : 0, 2)) |
| Skattepligtig | taxable | ($b := afterAm - $const.personalAllowance; $round($b > 0 ? $b : 0, 2)) |
| Bund + kommuneskat | bottomMunicipal | $round(taxable * ($const.bottomRate + municipalRate), 2) |
| Mellemskat | mellemTax | $round(afterAm > $const.mellemThreshold ? (afterAm - $const.mellemThreshold) * $const.mellemRate : 0, 2) |
| Topskat | topTax | $round(afterAm > $const.topThreshold ? (afterAm - $const.topThreshold) * $const.topRate : 0, 2) |
| Top Top Tax | topTopTax | $round(grossAnnual > $const.topTopThreshold ? (grossAnnual - $const.topTopThreshold) * $const.topTopRate : 0, 2) |
| Netto / år | netAnnual | $round(grossAnnual - amBidrag - atp - bottomMunicipal - mellemTax - topTax - topTopTax, 2) |
| Netto / måned | netMonthly | $round(netAnnual / 12, 2) |
Rates and thresholds
The expressions above read these as $const. They are the figures the annual refresh replaces, so they live as data rather than being written into the formulas — which is what makes a year-on-year change a one-line diff instead of an edit to arithmetic.
| Constant | Value |
|---|---|
atpAnnual | 1188 |
amRate | 0.08 |
personalAllowance | 54100 |
bottomRate | 0.1201 |
mellemThreshold | 641200 |
mellemRate | 0.075 |
topThreshold | 777900 |
topRate | 0.075 |
topTopThreshold | 2818152 |
topTopRate | 0.05 |
rateGennemsnit | 0.2543 |
rateKoebenhavn | 0.2339 |
rateHoejeste | 0.263 |
Test vectors (3)
Every case is executed against this model on each build, by the Java engine and independently by a JavaScript one. A mismatch of a single cent fails the build, so the page cannot ship advertising a figure the model no longer produces.
Case 1 — S1 420,000 DKK, average municipality
given grossAnnual | 420000 |
|---|---|
given kommune | anden |
given customMunicipalRate | 0.251 |
expect atp | 1188 |
expect amBidrag | 33504.96 |
expect afterAm | 385307.04 |
expect taxable | 331207.04 |
Case 2 — S3 900,000 DKK — mellemskat and topskat both bind
given grossAnnual | 900000 |
|---|---|
given kommune | anden |
given customMunicipalRate | 0.251 |
expect amBidrag | 71904.96 |
expect afterAm | 826907.04 |
expect mellemTax | 13928.03 |
expect topTax | 3675.53 |
Case 3 — S2 420.000 kr. i København — landets laveste kommuneskat
given grossAnnual | 420000 |
|---|---|
given kommune | koebenhavn |
expect municipalRate | 0.2339 |
expect bottomMunicipal | 117247.29 |
Sources
- Skattestyrelsen · checked 2026-08-02
Check it yourself — and reuse it
The whole model as JSON — inputs, outputs, formulas, vectors and sources in one re-runnable document.
This model is published under CC BY 4.0: use it, adapt it, build on it, with attribution. The licence covers the model — the expression of each rule and the arrangement of the catalog. The rates and thresholds are law, and nobody licenses those; the sources above are where they come from.
← Back to the Denmark løn efter skat calculator
Built with Valem — a live, verifiable calculator you can fork and embed.