Data Catalog - R2 Storage (landbruget-data)
Data lake with 130+ datasets across bronze/silver/gold medallion layers in Cloudflare R2.
Discovering Data
Use rclone to browse R2 — never use gsutil or google.cloud.storage.
# List top-level directories
rclone lsd r2:landbruget-data/
# List datasets in a layer
rclone lsd r2:landbruget-data/bronze/
rclone lsd r2:landbruget-data/silver/
rclone lsd r2:landbruget-data/gold/
# List snapshots (timestamped subdirectories) for a dataset
rclone lsd r2:landbruget-data/silver/subsidies/
# List files in a snapshot
rclone ls r2:landbruget-data/silver/subsidies/
# Find latest snapshot for a dataset
rclone lsd r2:landbruget-data/gold/field_production_2024/ | tail -1
Important: Some folder names contain spaces (e.g., silver/animal welfare/, silver/work permits/). Always quote paths when scripting.
Reading Data with DuckDB
DuckDB with R2 auth is the primary way to query data. Use StorageAccess from backend/common/storage/core.py:
from common.storage.core import StorageAccess
storage = StorageAccess()
# Read a parquet file into DuckDB
storage.create_table_from_storage_parquet("my_table", "landbruget-data/silver/subsidies/20260401_020000/data.parquet")
# Query it
result = storage.execute_query("SELECT cvr_number, COUNT(*) FROM my_table GROUP BY cvr_number")
Or use DuckDB directly after auth setup:
import duckdb
from common.storage.filesystem import setup_duckdb_cloud_auth
conn = duckdb.connect()
setup_duckdb_cloud_auth(conn)
# Query directly from R2
result = conn.execute("""
SELECT cvr_number, SUM(area_ha) as total_area
FROM read_parquet('r2://landbruget-data/gold/field_production_2024/*/data.parquet')
GROUP BY cvr_number
""").fetchdf()
Environment Variables
# R2 credentials (required)
R2_ACCESS_KEY_ID=<access-key>
R2_SECRET_ACCESS_KEY=<secret-key>
R2_ACCOUNT_ID=<account-id>
# Bucket name (defaults to "landbruget-data")
R2_BUCKET=landbruget-data
# Or: STORAGE_BUCKET=landbruget-data
Medallion Architecture
bronze/ — Raw data exactly as received (133 datasets)
silver/ — Cleaned, validated, standardized (126 datasets)
gold/ — Analysis-ready, joined datasets (86 datasets)
Full Dataset Inventory
Bronze (133 datasets)
| Category |
Datasets |
| Fields |
agriculturalblocks{2020-2024}, agriculturalfields{2020-2025}, fields |
| FVM Marker |
fvmmarker{2008-2025}, fvmmarkersmaabiotoper_{2023-2025} |
| FVM Markblokke |
fvmmarkblokke{2005-2026} |
| Organic |
fvmorganicareas{2012-2024}, fvmorganicsubsidies{2019-2024} |
| Subsidies |
subsidies, fvmenvironmentalsubsidies{2019-2023}, fvmgrasslandsubsidies{2019-2024} |
| Jordbrugsanalyser |
jordbrugsanalysermarkers{2012-2024} |
| Cadastral/Geo |
cadastral, dagikommuner, dagilandsdele, dagipostnumre, dagiregioner, bbr_buildings |
| Environment |
bnbostatus, wetlands, soiltypes, waterprojects, watertypology (3 datasets), grukos (2 datasets), fertiliser |
| Pesticides |
pesticides, bmd, geusdataversepesticides, kemidatasurfacewater_pesticides |
| Livestock |
chr, animalwelfare, animalmortality, animalinternationalmovements, pigtailcutting, slurryleaks, stablefires, transportation_accidents |
| Companies |
cvrrawcompanies, dst, dmi |
| Workers |
arbejdstilsynetinspections, workpermits, worker_safety |
Silver (126 datasets)
| Category |
Datasets |
| Fields |
fvmmarker{2008-2025}, fvmmarkblokke{2005-2026}, fvmsmaabiotoper{2023-2025}, fields |
| Organic |
fvmorganicareas{2012-2023}, fvmorganicsubsidies{2019-2024} |
| Subsidies |
subsidies, fvmenvironmentalsubsidies{2019-2023}, fvmgrasslandsubsidies{2019-2024} |
| Cadastral/Geo |
cadastral, dagikommuner, dagilandsdele, dagipostnumre, dagiregioner, bbrbuildings, dstzonemapping, dstzonemappingreference |
| Environment |
bnbostatus, bnbostatusdissolved, wetlands (implied), grukos, grukos*dissolved (2), waterprojects, waterprojectsdissolved, fertiliser |
| Pesticides |
pesticides, bmd, geusdataversepesticides, geusdataversepesticides_pfas |
| Livestock |
chr, svineflytning, animal welfare, animal mortality, animal international movements, pig tail cutting, slurry leaks, stable fires, transportation accidents |
| Companies |
cvrcompanies, cvremployment, cvrpersons, propertyowners |
| Workers |
arbejdstilsynet_inspections, work permits, worker safety |
| Legacy/Other |
2016* (4 datasets), gr {2015-2023} (8 datasets), froprocessed, gartn1processed, halm1processed, hst77_processed |
Gold (86 datasets)
| Category |
Datasets |
| Field Production |
fieldproduction{2008-2025} (18 years) |
| Field Analysis |
fieldanalysisfieldbnbointersections{2024,2025}, fieldanalysisfieldbnbowaterintersections{2024,2025}, fieldanalysisfieldgrukosintersections{2024,2025}, fieldanalysisfieldwetlandintersections{2024,2025}, fieldanalysisfieldwetlandwaterintersections{2024,2025}, fieldanalysissoilintersections{2024,2025}, fieldanalysiswaterprojectsbnbointersections{2024,2025}, fieldanalysiswaterprojectswetlandsintersections{2024,2025}, fieldanalysiswetlandwater_coverage |
| Environmental Analysis |
fieldenvironmentalanalysisfields{2024,2025}, fieldenvironmentalanalysisproperties{2024,2025} |
| Pesticides |
pesticidedisaggregation{20102011 through 20232024} (13 year-pairs), pesticideproximity{20102011 through 20232024} (13 year-pairs) |
| Pre-computed stages |
stage0bnbofiltered{2024,2025}, stage0grukosfiltered{2024,2025}, stage0propertiesfiltered{2024,2025}, stage0soiltypesfiltered{2024,2025}, stage0waterprojectsfiltered{2024,2025}, stage0wetlandsfiltered{2024,2025} |
| Livestock |
chrtimelinesummary, chrveterinarytimeline |
| Companies |
cvrenrichment, cvrenrichmentcollection, cvrenrichmentcompanies, cvrenrichmentfinancial, cvrenrichmentfinancialstatements, cvrenrichmentpnumbers |
| Cadastral |
propertycadastralmerged |
Other Top-Level
api/ — API-related data
cvr_collections/ — CVR collection data
Key Identifiers
| Identifier |
Format |
Description |
Validation |
| CVR |
8 digits |
Company registration number |
^\d{8}$ |
| CHR |
6 digits |
Central Husbandry Register (herd ID) |
^\d{6}$ |
| BFE |
Variable |
Cadastral parcel number |
varies |
| field_id |
String |
Field identifier from FVM |
varies |
| field_uuid |
UUID |
Unique field identifier |
UUID format |
Dataset Quick Reference
Okonomi (Finance)
| Dataset |
Path |
Rows |
Key Columns |
| Subsidies |
silver/subsidies/ |
554K |
cvr_number, tilskudsberetigt |
| CVR Enrichment |
gold/cvr_enrichment/ |
varies |
cvr_number, company data |
| Property Owners |
silver/property_owners/ |
8.2M |
CVRNummer, owner info |
Landbrugsareal (Agricultural Land)
| Dataset |
Path |
Rows |
Key Columns |
| FVM Marker (fields) |
silver/fvmmarker{year}/ |
617K/year |
fieldid, cvrnumber, crop_code, geometry |
| Field Production |
gold/fieldproduction{year}/ |
617K/year |
fieldid, yieldestimate, crop_type |
| Cadastral |
silver/cadastral/ |
2.16M |
bfe_number, geometry |
Miljo (Environment)
| Dataset |
Path |
Rows |
Key Columns |
| Pesticide Disaggregation |
gold/pesticidedisaggregation{year}/ |
1.52M |
cvr_number, PesticideName, DosageQuantity |
| BNBO Status |
silver/bnbo_status/ |
5.4K |
geometry, status_bnbo |
| Wetlands |
silver/wetlands/ (in bronze) |
1.7M |
geometry, toerv_pct |
Husdyr (Livestock)
| Dataset |
Path |
Rows |
Key Columns |
| Svineflytning |
silver/svineflytning/ |
1.27M |
senderchrnumber, receiverchrnumber, total_animals |
| CHR Movements |
bronze/chr/ |
124K |
reportingherdnumber, animal_count |
| Animal Welfare |
silver/animal welfare/ |
varies |
chr_number |
Medarbejdere (Employees)
| Dataset |
Path |
Rows |
Key Columns |
| Arbejdstilsynet |
gold/arbejdstilsynet_inspections/ |
536 |
cvrnumber, decision, severityscore |
| Work Permits |
silver/work permits/ |
varies |
cvr_number |
| Worker Safety |
silver/worker safety/ |
varies |
cvr_number |
Cross-Dataset Joins
CVR-based joins (most common)
# Join subsidies with pesticides on CVR using DuckDB
conn.execute("""
SELECT s.cvr_number, s.tilskudsberetigt, p.PesticideName
FROM read_parquet('r2://landbruget-data/silver/subsidies/*/data.parquet') s
JOIN read_parquet('r2://landbruget-data/gold/pesticide_disaggregation_2023_2024/*/data.parquet') p
ON s.cvr_number = p.cvr_number
""")
Field-based joins
# Join field production with environmental analysis
conn.execute("""
SELECT fp.field_id, fp.yield_estimate, fe.bnbo_overlap_pct
FROM read_parquet('r2://landbruget-data/gold/field_production_2024/*/data.parquet') fp
JOIN read_parquet('r2://landbruget-data/gold/field_environmental_analysis_fields_2024/*/data.parquet') fe
ON fp.field_id = fe.field_id
""")
Data Update Schedule
| Layer |
Frequency |
Notes |
| Bronze |
Weekly (Mondays 2AM UTC) |
Immutable, timestamped |
| Silver |
After bronze update |
Cleaned, validated |
| Gold |
After silver update |
Analysis-ready |
Related Skills
- okonomi/ - Financial data: subsidies, property values
- landbrugsareal/ - Field and crop data: FVM marker, production
- miljo/ - Environmental data: pesticides, nitrogen, BNBO
- husdyr/ - Livestock data: CHR, movements, welfare
- medarbejdere/ - Employee data: inspections, safety
Troubleshooting
Check R2 access
rclone lsd r2:landbruget-data/
If rclone fails
Check ~/.config/rclone/rclone.conf has an [r2] section with:
type = s3
provider = Cloudflare
accesskeyid and secretaccesskey
endpoint pointing to your R2 account
Large Files
Use DuckDB — never load large parquet files into Pandas:
conn.execute("""
SELECT cvr_number, SUM(area_ha) as total_area
FROM read_parquet('r2://landbruget-data/gold/field_production_2024/*/data.parquet')
GROUP BY cvr_number
""").fetchdf()
CRS
All geometry stored in EPSG:4326 (WGS84) in Supabase. Bronze/Silver/Gold processing uses EPSG:25832 (UTM 32N).