Administrative boundaries of Italy — regions, provinces and municipalities — as GeoJSON and TopoJSON, in WGS84 (EPSG:4326).
The repository answers two questions:
- What are Italy's administrative boundaries now? Download a file. No build step, no interpreter, no dependency on this project's tooling.
- What were they on a given date? The same boundaries as ISTAT published them for that date, back to 21 October 2001 — including the changes that took effect inside the year, which an annual series cannot represent.
Everything here is derived from ISTAT and redistributed under CC-BY. Every figure in this file is measured, not estimated.
Breaking change in release 2026.1. The Sardinian reform effective 1 January 2026 renumbered every Sardinian province — codes 90, 91, 92, 95 and 111 are vacant, the new units occupy 112 to 119 — and with them all 377 Sardinian
com_istat_codevalues, with no overlap against the previous release. Join oncom_catasto_code, which is stable across the reform. See the CHANGELOG before upgrading.
The files at the root of this repository are the 1 January 2026 ISTAT vintage. Pin them directly:
https://raw.githubusercontent.com/guglielmo/geojson-italy/main/<path>
Full vertex count, one layer per file, compatible with almost every visualiser and library.
| File | Contents |
|---|---|
geojson/limits_IT_municipalities.geojson |
all 7,896 municipalities, ~40 MB |
geojson/limits_IT_provinces.geojson |
all 110 provinces and metropolitan cities |
geojson/limits_IT_regions.geojson |
all 20 regions |
geojson/limits_R_{code}_municipalities.geojson |
municipalities of one region — e.g. R_12, Lazio |
geojson/limits_P_{code}_municipalities.geojson |
municipalities of one province — e.g. P_58, Rome |
{code} is the ISTAT numeric code without zero padding, while the prov_istat_code and
reg_istat_code properties are zero-padded strings. Both forms exist on purpose;
*_istat_code_num is the integer.
A file is emitted for every code in range even where no province survives, so a vacant code
returns an empty GeometryCollection rather than a 404 — the URL stays stable.
Since release 2023.1 the GeoJSON files are written with mapshaper's gj2008 flag, which
emits pre-RFC 7946 GeoJSON (winding order and the crs member). This is what keeps them
working with D3 and everything built on it, Plotly included — see
mapshaper#432.
Smaller, less precise, and able to carry several layers in one file. Shared borders stay topologically coincident across the three levels, because provinces and regions are dissolved from the already simplified municipalities.
| File | Contents |
|---|---|
topojson/limits_IT_all.topo.json |
municipalities, provinces and regions in three layers, ~4 MB |
topojson/limits_IT_municipalities.topo.json |
municipalities, one layer |
topojson/limits_IT_provinces.topo.json |
provinces |
topojson/limits_IT_regions.topo.json |
regions |
topojson/limits_R_{code}_municipalities.topo.json |
municipalities of one region |
topojson/limits_P_{code}_municipalities.topo.json |
municipalities of one province |
GitHub previews GeoJSON only below a size limit and never previews TopoJSON; use mapshaper.org for the larger files.
Metropolitan cities are second-level units alongside provinces. They are inside
limits_IT_provinces as they have always been — Rome is 058, and the file still holds all
110 units — and they now also have a layer of their own:
| File | Contents |
|---|---|
geojson/limits_IT_metropolitan_cities.geojson |
the 15 città metropolitane |
prov_tipo_uts distinguishes all five ISTAT unit types — Provincia (83), Città metropolitana
(15), Libero consorzio di comuni (6), Unità non amministrativa (4), Provincia autonoma (2) —
so any other split can be made with a filter.
Note that ISTAT gives metropolitan cities two codes and its own products disagree on
which to show: the boundary shapefiles use COD_PROV 112 for Sassari and 118 for Cagliari,
the codes list uses COD_UTS 312 and 318. This repository has always published the
COD_PROV family.
| Property | On | Meaning |
|---|---|---|
name |
M | municipality name |
com_catasto_code |
M | cadastral (Belfiore) code, e.g. H501 |
com_istat_code / com_istat_code_num |
M | ISTAT code, zero-padded string / integer |
op_id |
M | openpolis id, for integration with legacy OP data |
opdm_id |
M | opdm id |
minint_elettorale |
M | interior ministry id |
minint_finloc |
M | interior ministry id used in Finanza Locale statements |
prov_name |
M, P | province name |
prov_istat_code / prov_istat_code_num |
M, P | province ISTAT code |
prov_acr |
M, P, R | province acronym, e.g. RM |
prov_iso_3166_2 |
M, P | province ISO 3166-2 code, e.g. IT-RM, or null |
prov_uts_code |
M, P | ISTAT's other code family for second-level units: 312 Sassari, 318 Cagliari, against COD_PROV 112 and 118 |
prov_tipo_uts |
M, P | Provincia, Provincia autonoma, Città metropolitana, Libero consorzio di comuni, Unità non amministrativa |
reg_name |
M, P, R | region name |
reg_istat_code / reg_istat_code_num |
M, P, R | region ISTAT code |
reg_iso_3166_2 |
M, P, R | region ISO 3166-2 code, e.g. IT-62 |
M = municipalities, P = provinces, R = regions. Municipality-only properties do not survive the dissolve into provinces and regions.
ISO numbers the regions on a scheme of its own, unrelated to ISTAT's: Piedmont is ISTAT 01
and ISO IT-21.
prov_iso_3166_2 is null for five of the 110 second-level units, and that is correct.
ISO 3166-2:IT defines no code for Valle d'Aosta (the region exercises provincial
functions, so IT-AO was deleted in 2019) nor for the four Sardinian units created in 2026
— Gallura Nord-Est Sardegna, Ogliastra, Medio Campidano, Sulcis Iglesiente.
Those four bear vehicle plates matching codes ISO withdrew in April 2019, so filling the
gap from prov_acr would publish identifiers the standard no longer defines. 175
municipalities are affected; they still carry reg_iso_3166_2.
Administrative geography moves constantly: since 2001 municipalities have merged, split, been renumbered and been reassigned to other provinces on 98 distinct dates, and 72 of those fall inside the year. A series published only at 1 January cannot answer for them — it returns a plausible, wrong answer with no error.
Each publication date has a GitHub Release tagged with that date, carrying the same shape of file set as the root of the repository. Nothing to build, nothing to filter:
curl -LO https://github.com/guglielmo/geojson-italy/releases/download/2005-01-01/limits_IT_municipalities.geojson.gz| Asset | 2005-01-01 |
|---|---|
limits_IT_municipalities.geojson.gz |
8,101 municipalities |
limits_IT_provinces.geojson.gz |
103 provinces |
limits_IT_metropolitan_cities.geojson.gz |
0 — metropolitan cities were instituted in 2015 |
limits_IT_regions.geojson.gz |
20 regions |
limits_IT_all.topo.json.gz |
the three layers, simplified to 20% |
Provinces and regions are dissolved from the municipalities of that date, so the file set describes the country as it was, not today's boundaries backdated. Every asset is gzipped, which every common tool reads directly.
Which tag do I want? For a year, take its 1 January — 2005-01-01 — which is what
"the 2005 boundaries" almost always means. If you have an exact date, look it up in
temporal/INDEX.csv: one row per validity interval, saying which
release serves it and what changed on that date.
valid_from,valid_to,release_tag,municipalities,change
2005-01-01,2005-05-04,2005-01-01,8101,16 admin_variazione_territoriale
2005-05-04,2005-05-11,2005-05-04,8101,1 admin_cambio_denominazione
2005-05-11,2006-01-01,2005-05-11,8101,1 admin_cambio_denominazioneThis matters more than it looks. 72 of the 98 dates fall inside the year, so for a date like
10 September 2021 both the 2021 and the 2022 January editions are wrong — Misiliscemi was
established on 20 February 2021, and Montecopiolo and Sassofeltrio were recoded on 17 June.
The index resolves it to 2021-06-17.
Per-region and per-province subsets (limits_R_*, limits_P_*) are produced for the current
vintage only.
ISTAT draws boundaries once a year, on 1 January. Codes, names and provincial assignment are exact for the date you asked for — those change on the day the act says. Boundaries are the ones ISTAT last published, so at a date inside the year they come from that year's 1 January edition. A change of code or of province, which is the common case, moves no boundary and is represented exactly; a boundary moved by a transfer of territory appears at the following edition.
Do not read a diff between two dates as administrative change. ISTAT re-generalises its
geometries in some editions and not others — 2002, 2010, 2011, 2012, 2019, 2022 and 2025 — so
comparing two adjacent years shows roughly 7,900 changed boundaries and means nothing
happened. Every feature carries version_reason: source_regeneralization is ISTAT redrawing
its own lines, source_attribute_change is a published field changing with the boundary
untouched, and the admin_* values are the real events. Filter on it.
A municipality ISTAT had not yet drawn says so in source_edition:
(union of predecessors) where a merger's boundary is its predecessors' dissolved together,
(anticipated) where a detached municipality's boundary is taken from the next edition that
carries it. 39 municipalities across 42 dates are in this position; the rest carry a boundary
read from a named ISTAT file, which is what makes the fidelity claim checkable.
The historical archive lives in temporal/, holds 8,231 municipalities in
78,325 versions, and is the repository's source of truth: the current files above and every
release asset are derived from it. Read it directly only if you want the whole history at
once — for a single date, take the release.
temporal/
├── comuni/reg=NN.geojson one file per region, each feature carrying a validity interval
├── SCHEMA.md every field, and what is checked
└── INDEX.csv validity interval -> release tag (not published yet)
Each feature is one municipality over one validity period, so a date is an interval filter:
mapshaper -i temporal/comuni/reg=12.geojson \
-filter 'valid_from <= "2021-09-10" && (!valid_to || valid_to > "2021-09-10")' \
-o boundaries_2021-09-10.geojsonWhy GeoJSON rather than a database format. Parquet would be smaller and directly queryable. It is rejected anyway: verifying this archive should require mapshaper, already this project's only dependency, not a database engine. Split by region so a change touching one region rewrites one file.
Read temporal/SCHEMA.md before using it. Two things beyond the
caveats above are not self-evident:
- The key is
terr_key, the municipality's first cadastral code — never the ISTAT code. The ISTAT code embeds the province, so it changes on reassignment; the 2026 Sardinian reform changed 377 of them with zero overlap. Measured across the series, exactly one municipality ever changed its own cadastral code and no code was ever reused. - Gaps are meaningful. Baranzate was constituted in 2001, abolished in 2003 when the Constitutional Court struck down the regional law behind it, and constituted again in 2004. Its intervals have a hole, on purpose.
The archive is faithful to what ISTAT published for each date, and is not smoothed,
normalised or reconciled. source_edition names the file each geometry was read from, so
the claim can be checked by downloading it.
The older release tags (2019, 2021.1, 2021.2, 2022.1, 2023.1, 2026.1, 2026.2)
record what this repository published at those moments, which is a different fact from what
ISTAT published for those reference dates. They stay untouched, and the ISO-date tags cannot
collide with them.
Everything comes from ISTAT, over anonymous HTTP, with no credentials.
| Layer | Source |
|---|---|
| Geometry | The generalised boundary editions, one per reference date. 26 editions, 2001–2026, checksummed in build/editions/MANIFEST.json. |
| Codes, names, provincial and regional assignment | The SITUAS roster of territorial units, which answers with the complete list of municipalities valid on any date since 1948. |
| Why each version exists, and under which act | The SITUAS variation reports, covering municipal variations from 1991 and suppressions, renamings and code changes from the 1860s. |
Two facts about the sources are load-bearing and easy to get wrong:
- The census editions do not describe 1 January.
Limiti2001_gcontains Fonte Nuova, constituted 15 October 2001, andLimiti2011_gcontains Gravedona ed Uniti, constituted 11 February 2011, in place of the three municipalities it replaced. They describe their census date. This is why the series starts on 21 October 2001 rather than in January: for the preceding nine months ISTAT published no boundaries at all, and those dates are not served rather than served with a boundary set that does not describe them. -proj wgs84is required when converting the shapefiles. The_WGS84in the ISTAT filenames names the datum; the.prjisWGS_1984_UTM_Zone_32Nin metres.
The two products agree: the municipality count in the boundary edition matches ISTAT's own roster for 24 of 26 years, and the two exceptions are the census editions above.
Requires mapshaper (node) — verified against 0.6.29,
which generated release 2026.1, and 0.6.65 — and Python 3 for the fetch and build scripts.
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
# the historical archive, from ISTAT to temporal/
.venv/bin/python -m scripts.fetch_editions # 26 boundary editions, ~300 MB
.venv/bin/python -m scripts.fetch_situas variations # the variation reports
.venv/bin/python -m scripts.fetch_situas rosters # the roster at each of the 98 dates
.venv/bin/python -m scripts.build_temporal build
.venv/bin/python -m scripts.validate_temporal
# the current vintage, and the files derived from it
./scripts/fetch_sources.sh 2026
cp comuni.geojson comuni.geojson.prev
.venv/bin/python -m scripts.build_comuni 2026
./generate_geojson.sh
./generate_topojson.sh
.venv/bin/pytest tests/Please ask SITUAS sparingly. It answers one request at a time and returns 503 to some
client addresses for stretches at a time. The fetcher pauses between requests, retries
slowly, caches everything and takes --limit N to spread the first fill across sessions.
The build checks itself. validate_temporal verifies that no entity has overlapping
validity periods, that the municipality count matches ISTAT's roster at every one of the 98
dates, and that all 377 Sardinian municipalities resolve to the same key across the 2026
reform — the event that breaks any dataset keyed on the ISTAT code.
Older releases were built by hand following this wiki page, which the scripts above supersede.
guglielmo/geojson-italy, previously
openpolis/geojson-italy. The default branch was renamed master → main in August 2026.
GitHub redirects both the old owner and the old branch name, raw.githubusercontent.com
included, so existing pinned URLs keep working — but a redirect is a convenience, not a
guarantee. Update pinned URLs to owner guglielmo and branch main.
The administrative limits are copyrighted by ISTAT and released under CC-BY. The data generated and published here are released under the same licence. Keep the ISTAT attribution when redistributing.