Loading workbench page
Fetching primary parquet sources and computing exhibits.
Fetching primary parquet sources and computing exhibits.
Aggregate EU statistics hide a regional economy that is more unequal within countries than between them. This page opens the NUTS2 lens, roughly 240 sub-national units ranging from Île-de-France to Bulgaria's Severozapaden, and asks seven questions: which regions produce the most output, which are richest and poorest, how does the EU's own Cohesion Policy typology sort them, has Europe converged or diverged since 2000, where is within-country inequality concentrated, how does sectoral composition relate to regional prosperity, and where are knowledge jobs concentrated. Everything is pulled live from Eurostat's regional accounts (NAMA_10R_2GDP for GDP, NAMA_10R_2GVAGR for gross value added by NACE sector), NUTS 2021 vintage.
At the top of the European regional hierarchy sits Île-de-France: Paris and its commuter belt produce more output than any other NUTS2 region in Europe, and more than the combined GDP of several smaller member states. Iammarino, Rodríguez-Pose & Storper (2019, Journal of Economic Geography) document that the European growth story of the last quarter-century has not been a uniform 'rising tide' but a re-concentration of activity into a handful of capital-city and metropolitan regions, the NUTS2 analogue of Moretti's (2012) divergent labour-market geography in the United States. The absolute-size ranking below is the first fingerprint of that pattern.
SELECT geo, year, value
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'MIO_EUR'
AND value IS NOT NULL
AND LENGTH(geo) = 4
AND year = (
SELECT year
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'MIO_EUR' AND value IS NOT NULL AND LENGTH(geo) = 4
GROUP BY year HAVING COUNT(*) >= 250
ORDER BY year DESC LIMIT 1
)
ORDER BY value DESC
LIMIT 20;Switching from absolute levels to GDP per inhabitant reveals the stark European welfare gradient. Luxembourg and Ireland's two NUTS2 regions lead the per-capita ranking (both uplifted by cross-border commuting and multinational profit booking respectively), joined above €80,000 per head by Copenhagen (DK01), Hamburg (DE60), Brussels (BE10), and Amsterdam (NL32); at the other end, Bulgaria's Severozapaden and Romania's Nord-Est anchor the bottom of the EU27 ranking, at roughly €10,000-12,000 per head. Gagliardi & Percoco (2017, Regional Studies) show in their impact evaluation of European Cohesion Policy that these lagging regions are precisely the ones where EU structural funds generate the largest growth effects, but only when absorptive capacity (local governance, human capital) is sufficient, a pattern that helps explain why the per-capita gap between top and bottom has closed only modestly over two decades.
The EU's own regional policy framework, set out in the Common Provisions Regulation 2021/1060 (Article 108), sorts NUTS2 regions into three eligibility tiers based on GDP per inhabitant in purchasing power standards (PPS) relative to the EU27 average. PPS strips out price-level differences across countries, so a given PPS index value is comparable in real-consumption terms across the Union, which is why the ESPON territorial-cohesion framework and the 9th Cohesion Report (European Commission 2024) both use this index rather than euro figures. The three tiers are: less developed (below 75% of the EU27 mean), transition(75% to below 100%), and more developed (at or above 100%).
Regional convergence is measured most plainly as the dispersion of per-capita GDP across NUTS2 units over time, the classical σ-convergence statistic proposed by Sala-i-Martin (1996, European Economic Review). Iammarino, Rodríguez-Pose & Storper (2019) argue that European regional convergence is a 'twin-peaks' story: between-country catch-up of the 2004 accession states is real, but within-country divergence has widened almost everywhere, leaving overall dispersion broadly stable. The chart tracks the coefficient of variation (CV) of NUTS2 GDP per capita across all EU27 regions from 2000 to 2024; a falling CV means regions are becoming more alike, a rising CV means they are pulling apart.
National-average GDP per capita hides a within-country distribution that is wider in some EU members than in others. The figure below shows the Gini coefficient of NUTS2 GDP per capita within each EU27 country (restricted to members with at least three NUTS2 units). Iammarino, Rodríguez- Pose & Storper (2019) argue that within-country dispersion is the policy-relevant margin, the one that produces populist backlash, inter-regional fiscal conflict, and the 'places that don't matter' dynamic, and it is systematically higher in the newer member states and in the old Mediterranean members where a metropolitan capital vastly out-produces the rest of the country.
What do the rich regions do? The NACE Rev. 2 breakdown in Eurostat's regional gross value added table (NAMA_10R_2GVAGR) lets us aggregate information & communication (section J), financial & insurance activities (K), and professional / scientific / technical / administrative services (M_N) into a single 'knowledge-intensive market services' bundle, then plot each NUTS2 region's share of GVA in this bundle against its GDP per inhabitant. The logic follows Gennaioli, La Porta, Lopez-de-Silanes & Shleifer (2013, Quarterly Journal of Economics), whose cross-regional human-capital decomposition shows that the share of GVA produced in high-skill services is one of the strongest predictors of regional income per head once initial-level effects are partialed out.
Knowledge-intensive services share of GVA in Figure 6 is a value-added composition measure; high-tech employment per inhabitant is a labour- market complement, asking not how much output the high-skill sectors produce but how many people they actually employ relative to the local population. Eurostat's high-tech employment series at NUTS2 (HTEC_EMP_REG2) follows the OECD-Eurostat NACE Rev. 2 high-technology aggregation (manufacture of basic pharmaceuticals C21, computer and electronics C26, air and spacecraft C30, plus high-tech knowledge-intensive services). Population is implied as MIO_EUR / EUR_HAB for the same region and year, so the per-1,000-inhabitants metric is internally consistent with the rest of this page. The capital-region concentration of high-tech jobs is the mechanism behind the Iammarino, Rodríguez-Pose & Storper (2019) development trap: knowledge employment agglomerates in metropolitan cores faster than incomes spread out.
Europe's regional economy is a Paris-and-the-big-capitals story at the absolute-size level, a Luxembourg-and-Dublin-versus-Severozapaden story at the per-capita level, and a majority-of-the- map-still-below-the-EU27-average story once PPS adjustment is applied. It is a convergence- interrupted story over 2000-2024, a within-country-divergence story at the member-state level, and a knowledge-services-intensity story in the cross-section of NACE shares. The seven findings are jointly consistent with the Iammarino-Rodríguez-Pose-Storper (2019) 'development trap' framing: nominal catch-up of poorer regions is real but slow, capitals continue to pull ahead of their hinterlands, sectoral composition (not just capital deepening) drives most of the persistent income gap, and the policy-relevant inequality is within rather than between countries. Gagliardi & Percoco (2017) identify absorptive capacity as the binding constraint on Cohesion-Policy effectiveness; the stylised facts above are why that constraint matters. Every figure is reproducible from data/parquet/eu_nuts2_gdp.parquet and data/parquet/eu_nuts2_gva.parquet using the SQL blocks printed alongside each figure.
Method notes. NUTS2-level GDP is read from Eurostat's regional accounts dataset NAMA_10R_2GDP (retrieved April 2026), filtered to 4-character geo codes to isolate NUTS2 from NUTS0/NUTS1 aggregates. Absolute-size comparisons use MIO_EUR (current prices); market-exchange-rate per-capita comparisons use EUR_HAB; the Cohesion Policy typology uses PPS_HAB_EU27_2020, which is GDP per inhabitant expressed in purchasing power standards indexed so that the EU27 mean equals 100. PPS is the unit that Article 108 of Regulation (EU) 2021/1060 and the Ninth Cohesion Report (European Commission 2024) use to assign regions to the less-developed / transition / more- developed tiers. Sectoral composition (Figure 6) is from NAMA_10R_2GVAGR at basic prices, NACE Rev. 2 aggregates. For the CV and Gini calculations, the EU27 is restricted to the current member states via Eurostat's two-letter country prefixes (note EL, not GR, for Greece). Single-region member states are dropped from the within-country Gini. NUTS definitions follow the NUTS 2021 vintage throughout.
SELECT geo, value
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'EUR_HAB'
AND year = <latest broadly-reported year>
AND value IS NOT NULL
AND LENGTH(geo) = 4
AND SUBSTR(geo, 1, 2) IN ('AT','BE','BG','HR','CY','CZ','DK','EE','FI','FR',
'DE','EL','HU','IE','IT','LV','LT','LU','MT','NL',
'PL','PT','RO','SK','SI','ES','SE')
ORDER BY value DESC;
-- Top 20 + bottom 20 plotted.WITH r AS (
SELECT geo, value
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'PPS_HAB_EU27_2020'
AND year = <latest year>
AND value IS NOT NULL AND LENGTH(geo) = 4
AND SUBSTR(geo, 1, 2) IN (<EU27 list>)
)
SELECT
SUM(CASE WHEN value < 75 THEN 1 ELSE 0 END) AS less_developed,
SUM(CASE WHEN value >= 75 AND value < 100 THEN 1 ELSE 0 END) AS transition,
SUM(CASE WHEN value >= 100 THEN 1 ELSE 0 END) AS more_developed
FROM r;SELECT year,
COUNT(*) AS n,
AVG(value) AS mean,
STDDEV_POP(value) AS sd,
100.0 * STDDEV_POP(value) / AVG(value) AS cv_pct
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'EUR_HAB' AND value IS NOT NULL AND LENGTH(geo) = 4
AND SUBSTR(geo, 1, 2) IN (<EU27 list>)
GROUP BY year
ORDER BY year;WITH tbl AS (
SELECT SUBSTR(geo,1,2) AS cc, geo, value
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'EUR_HAB' AND year = <latest> AND value IS NOT NULL
AND LENGTH(geo) = 4 AND SUBSTR(geo,1,2) IN (<EU27 list>)
),
ranked AS (
SELECT cc, value,
ROW_NUMBER() OVER (PARTITION BY cc ORDER BY value) AS r,
COUNT(*) OVER (PARTITION BY cc) AS k
FROM tbl
)
SELECT cc, k,
SUM((2*r - k - 1) * value) / (k * SUM(value)) AS gini
FROM ranked
GROUP BY cc
HAVING k >= 3
ORDER BY gini DESC;WITH g AS (
SELECT geo, year, nace_r2, value
FROM read_parquet('data/parquet/eu_nuts2_gva.parquet')
WHERE unit = 'CP_MEUR' AND value IS NOT NULL AND LENGTH(geo) = 4
AND SUBSTR(geo,1,2) IN (<EU27 list>)
AND year = <latest>
AND nace_r2 IN ('TOTAL','J','K','M_N')
),
piv AS (
SELECT geo, year,
SUM(CASE WHEN nace_r2='TOTAL' THEN value END) AS total,
SUM(CASE WHEN nace_r2 IN ('J','K','M_N') THEN value ELSE 0 END) AS knowledge
FROM g GROUP BY geo, year
),
pc AS (
SELECT geo, year, value AS pc
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet')
WHERE unit = 'EUR_HAB' AND LENGTH(geo) = 4
)
SELECT piv.geo, 100.0 * piv.knowledge / piv.total AS knowledge_share, pc.pc, piv.total
FROM piv JOIN pc USING (geo, year)
WHERE piv.total > 0
ORDER BY knowledge_share DESC;WITH y AS (
SELECT year, region_code AS geo, value AS htec_ths
FROM read_parquet('data/parquet/eu_nuts2_trade.parquet')
WHERE indicator = 'htec_employment_ths' AND value IS NOT NULL
AND LENGTH(region_code) = 4
AND SUBSTR(region_code, 1, 2) IN (<EU27 list>)
),
good AS (SELECT year FROM y GROUP BY year HAVING COUNT(*) >= 200 ORDER BY year DESC LIMIT 1),
emp AS (SELECT y.geo, y.year, y.htec_ths FROM y JOIN good USING (year)),
pop AS (
SELECT lvl.geo, lvl.year, lvl.value / pc.value AS pop_mn
FROM read_parquet('data/parquet/eu_nuts2_gdp.parquet') lvl
JOIN read_parquet('data/parquet/eu_nuts2_gdp.parquet') pc USING (geo, year)
WHERE lvl.unit = 'MIO_EUR' AND pc.unit = 'EUR_HAB'
AND lvl.value IS NOT NULL AND pc.value IS NOT NULL AND pc.value > 0
)
SELECT emp.geo, emp.htec_ths / pop.pop_mn AS per_1000
FROM emp JOIN pop USING (geo, year) ORDER BY per_1000 DESC LIMIT 20;