If someone is arrested in a small Brazilian town, three questions come before anything else: which judicial district (comarca) does the town belong to, which courthouse handles the case, and which prison unit receives the person. The answers exist, but they are scattered across the organisation acts of 27 state courts, the provisions of their inspectorates and the unit lists of 27 state prison administrations, almost never in the same place and almost never in a format you can join.
I am a criminal defense lawyer in Minas Gerais and I needed this map every week, so I built it as an open dataset: Brazil prison and court district map (Mapa prisional e de comarcas do Brasil).
What is in it
- One row per municipality: 2,167 of Brazil's 5,570 municipalities so far, in all 27 states.
- For each: the judicial district, the courthouse that serves it, and the prison units located in the municipality, with the primary source and the date each field was checked.
- A separate column for the reference unit (the prison in another town that receives detainees from that district), so an empty "units in town" cell is not read as "no information".
- Current version (2026-10-29): 280 municipalities with at least one unit inside their territory (348 units listed), 1,036 records stating, with a source, that the town has no unit, and 851 with no information yet.
No field is filled by estimation. If there is no official source, the cell stays empty.
Where to get it
- Zenodo (DOI, versioned): https://doi.org/10.5281/zenodo.23779474
- Mirrors: Kaggle, Harvard Dataverse (doi:10.7910/DVN/SP5MQT), Hugging Face, GitHub.
- Project page with the data dictionary: https://smargiassi.com.br/dados/mapa-prisional/
License: CC BY 4.0. Use it for anything, including commercial work, with attribution.
Quick start
import pandas as pd
# the CSV from the Zenodo record (version 2026-10-29); UTF-8 with BOM
df = pd.read_csv("mapa-prisional-brasil.csv", encoding="utf-8-sig")
# municipalities with at least one prison unit inside their territory
print((df["ha_unidade_no_municipio"] == "sim").sum())
# which district, courthouse and units serve a given town
cols = ["comarca", "forum", "unidades_no_municipio", "unidades_de_referencia", "fonte_ficha"]
print(df.loc[df["municipio"] == "Guaxupé", cols].T)
Every row also carries fonte_ficha, the URL of the municipal record page where each field cites its primary source and the date it was verified.
Why this matters beyond law
Researchers who study incarceration need a key that links the municipality, the unit of analysis of demographic statistics, to the judicial district, the unit of analysis of the courts. That key did not exist in open form. Journalists covering a prison riot or a court interdiction need to know which districts depend on a given unit. And agencies that publish prison data can use the map as a cross-check: a unit that appears in one source and not in the other is a sign that one of them is out of date.
How it was built, and how to fix it
The data comes from public documents: court organisation acts, inspectorate provisions and the unit lists of the state prison administrations, read one by one, with automation helping to collect and organise and a human checking every source. Errors are inevitable in a compilation like this; the fix is the same mechanism that made it possible. Every record points to its source, so a divergence can be checked at the origin, and corrections go out as new versions under the same DOI, with the history preserved.
If you find a mistake or have a better source for a state, open an issue on GitHub or write to felipe@smargiassi.com.br.
Top comments (0)