Wage trends in Germany from 2015 to 2025
Model: Kimi K2.6 Checked on:
Based on Eurostat’s Labour Cost Index data for Germany, nominal wages and salaries (excluding apprentices) in the broad economy (NACE B‑S: industry, construction and services) show a clear upward trend from 2015 to 2025, with a marked acceleration after 2021.
Key trend figures (annual index, 2020 = 100)12
| Year | Index | Annual growth |
|---|---|---|
| 2015 | 87.5 | +2.3 % |
| 2016 | 89.3 | +2.2 % |
| 2017 | 92.3 | +3.3 % |
| 2018 | 94.9 | +2.9 % |
| 2019 | 97.8 | +3.0 % |
| 2020 | 100.0 | +2.2 % |
| 2021 | 101.2 | +1.2 % |
| 2022 | 105.5 | +4.2 % |
| 2023 | 110.0 | +4.3 % |
| 2024 | 115.7 | +5.1 % |
| 2025 | 119.9 | +3.7 % |
Summary of the trend
- Steady, moderate growth (2015‑2020): Nominal wages rose at a fairly steady pace of roughly 2‑3 % per year, accumulating a 14 % increase over the five years before the pandemic.
- Pandemic slowdown (2021): Growth dropped to just 1.2 % in 2021, the lowest rate in the observed period.
- Sharp acceleration (2022‑2025): From 2022 onward wage growth picked up considerably, reaching 4‑5 % annually. 2024 saw the fastest increase at 5.1 %, while 2025 remained strong at 3.7 %. Over the full decade, the nominal wage level rose by about 37 %.
The quarterly, seasonally and calendar‑adjusted series confirms this pattern: a visible step‑up in year‑over‑year growth starting in 2022 and continuing through the latest available quarters31.
Visualisations of the index and growth rates are provided in the generated charts: the quarterly index trajectory 1, the annual growth‑rate bars 1, and the quarterly year‑over‑year growth profile 1.
- Code Run 1Dataset: lc_lci_r2_q Dataset: lc_lci_r2_a
Images
germany_wage_index_quarterly.svggermany_wage_growth_annual.svggermany_wage_growth_quarterly.svgDataset filters for
lc_lci_r2_qFilter Value(s) geo DE nace_r2 B-S lcstruct D11 unit I20, PCH_SM s_adj SCA sinceTimePeriod 2015 Dataset filters for
lc_lci_r2_aFilter Value(s) geo DE nace_r2 B-S lcstruct D11 unit I20, PCH_PRE sinceTimePeriod 2015 Program output
Annual Index values: year value 2015 87.5 2016 89.3 2017 92.3 2018 94.9 2019 97.8 2020 100.0 2021 101.2 2022 105.5 2023 110.0 2024 115.7 2025 119.9 Annual Growth rates: year value 2015 2.3 2016 2.2 2017 3.3 2018 2.9 2019 3.0 2020 2.2 2021 1.2 2022 4.2 2023 4.3 2024 5.1 2025 3.7 Plots saved successfully.Code
import pandas as pd import matplotlib.pyplot as plt # Load quarterly data df_q = pd.read_csv(DATASET_FILE0, low_memory=False) # Filter for B-S, D11, I20, SCA df_q_idx = df_q[(df_q['nace_r2'] == 'B-S') & (df_q['lcstruct'] == 'D11') & (df_q['unit'] == 'I20') & (df_q['s_adj'] == 'SCA')].copy() df_q_idx['period'] = pd.PeriodIndex(df_q_idx['time'], freq='Q') df_q_pch = df_q[(df_q['nace_r2'] == 'B-S') & (df_q['lcstruct'] == 'D11') & (df_q['unit'] == 'PCH_SM') & (df_q['s_adj'] == 'SCA')].copy() df_q_pch['period'] = pd.PeriodIndex(df_q_pch['time'], freq='Q') # Load annual data df_a = pd.read_csv(DATASET_FILE1, low_memory=False) df_a_idx = df_a[(df_a['nace_r2'] == 'B-S') & (df_a['lcstruct'] == 'D11') & (df_a['unit'] == 'I20')].copy() df_a_idx['year'] = df_a_idx['time'].astype(int) df_a_pch = df_a[(df_a['nace_r2'] == 'B-S') & (df_a['lcstruct'] == 'D11') & (df_a['unit'] == 'PCH_PRE')].copy() df_a_pch['year'] = df_a_pch['time'].astype(int) print("Annual Index values:") print(df_a_idx.sort_values('year')[['year','value']].to_string(index=False)) print("\nAnnual Growth rates:") print(df_a_pch.sort_values('year')[['year','value']].to_string(index=False)) # Plot 1: Quarterly Index fig, ax = plt.subplots(figsize=(10,6)) df_q_idx_sorted = df_q_idx.sort_values('period') # Convert period to timestamp for plotting x = df_q_idx_sorted['period'].dt.to_timestamp() ax.plot(x, df_q_idx_sorted['value'], marker='o', linestyle='-', markersize=3, color='navy') ax.set_title('Germany: Nominal Wages & Salaries Index (2020=100)\nNACE B-S, Seasonally and Calendar Adjusted') ax.set_xlabel('Quarter') ax.set_ylabel('Index (2020=100)') ax.grid(True, alpha=0.3) fig.autofmt_xdate() fig.tight_layout() fig.savefig('germany_wage_index_quarterly.svg', format='svg') plt.close() # Plot 2: Annual Growth Rate fig, ax = plt.subplots(figsize=(10,6)) df_a_pch_sorted = df_a_pch.sort_values('year') ax.bar(df_a_pch_sorted['year'], df_a_pch_sorted['value'], color='steelblue', edgecolor='black', linewidth=0.5) ax.set_title('Germany: Annual Growth Rate of Nominal Wages & Salaries (%)\nNACE B-S, Year-over-Year Change') ax.set_xlabel('Year') ax.set_ylabel('Percentage Change (%)') ax.axhline(0, color='red', linewidth=0.5) ax.grid(True, alpha=0.3, axis='y') fig.tight_layout() fig.savefig('germany_wage_growth_annual.svg', format='svg') plt.close() # Plot 3: Quarterly year-over-year growth fig, ax = plt.subplots(figsize=(10,6)) df_q_pch_sorted = df_q_pch.sort_values('period') x = df_q_pch_sorted['period'].dt.to_timestamp() ax.plot(x, df_q_pch_sorted['value'], marker='o', linestyle='-', markersize=3, color='green') ax.set_title('Germany: Quarterly Year-over-Year Growth of Nominal Wages & Salaries (%)\nNACE B-S, Seasonally and Calendar Adjusted') ax.set_xlabel('Quarter') ax.set_ylabel('Percentage Change (%)') ax.axhline(0, color='red', linewidth=0.5) ax.grid(True, alpha=0.3) fig.autofmt_xdate() fig.tight_layout() fig.savefig('germany_wage_growth_quarterly.svg', format='svg') plt.close() print("\nPlots saved successfully.") - Eurostat dataset: Labour cost index by NACE Rev. 2 activity - nominal value, annual data
- Eurostat dataset: Labour cost index by NACE Rev. 2 activity - nominal value, quarterly data