I run a small site that explains Swiss compliance rules for small businesses, and we recently added a calculator for occupational pension contributions.
In Switzerland that is the BVG (LPP in French), the second pillar every employer has to deal with once someone on the payroll earns enough.
It looks like a tangle of legal edge cases.
The mandatory minimum actually fits in four constants and two small functions, which is a nice change from most tax logic.
The four numbers
For 2026 the Federal Social Insurance Office publishes these limits:
| Constant | CHF per year |
|---|---|
| Entry threshold | 22,680 |
| Coordination deduction | 26,460 |
| Upper limit | 90,720 |
| Minimum coordinated salary | 3,780 |
An employee is only insured under the BVG minimum once their annual salary is above the entry threshold.
The retirement savings are then built on the coordinated salary, which is roughly the slice of the salary between the coordination deduction and the upper limit.
Coordinated salary
const ENTRY_THRESHOLD = 22_680;
const COORDINATION_DEDUCTION = 26_460;
const UPPER_LIMIT = 90_720;
const MIN_COORDINATED = 3_780;
export function coordinatedSalary(annualSalary: number): number {
if (annualSalary <= ENTRY_THRESHOLD) return 0; // not in the mandatory BVG
const capped = Math.min(annualSalary, UPPER_LIMIT);
return Math.max(capped - COORDINATION_DEDUCTION, MIN_COORDINATED);
}
The floor is the easy part to miss.
Someone earning CHF 25,000 is above the entry threshold, but 25,000 minus 26,460 is negative, so the law sets a minimum coordinated salary of CHF 3,780 instead.
Without the Math.max you quietly get negative contributions, and nothing crashes to tell you.
The cap works the other way.
Above CHF 90,720 the mandatory part stops growing, so the largest coordinated salary is CHF 64,260.
Age credits
The savings part depends on the age band:
export function ageCreditRate(age: number): number {
if (age < 25) return 0; // risk cover only, no retirement savings yet
if (age < 35) return 0.07;
if (age < 45) return 0.1;
if (age < 55) return 0.15;
return 0.18; // until retirement age
}
Under-25s are covered for death and disability but do not build retirement savings yet, which is why the first band returns 0.
A worked example
Take an employee aged 40 earning CHF 80,000 a year.
- Coordinated salary: 80,000 minus 26,460 = 53,540
- Age credit at 10%: 5,354 a year
- Employer share: at least half, so 2,677
That last line matters for employers.
The law makes the employer pay at least half of the total, and many pension funds split it more generously.
Things worth knowing before you build one
The limits move.
They are adjusted roughly every two years alongside the AHV pension, so keep them in one place together with the year you last checked them, not scattered through the UI.
These are legal minimums.
Plenty of pension funds insure more than the mandatory part, so the number an employee sees from their own fund can be higher.
The calculator shows the legal minimum.
Round only at the end.
Rounding the coordinated salary before applying the rate can leave you a franc or two off, which is exactly what an accountant will notice.
If you want to poke at it, the BVG contribution calculator runs this logic with the official limits, and each figure links to its source.
For the rest of what a Swiss employer owes, there is a page on employer obligations beyond the pension.
This is general information, not legal or pension advice.
Top comments (0)