Three repo contracts, not three tabs
The Hub treats models, datasets, and Spaces as different repository contracts — different URL prefixes, different metadata schemas, different storage backends, different rate limits. The web UI puts them under tabs, which makes them look like the same thing. They aren't.
huggingface.co/{org}/{name}— model repo. Holds weights (.safetensors/.bin), config, tokenizer, and aREADME.mdwith YAML front-matter (the model card).huggingface.co/datasets/{org}/{name}— dataset repo. Holds data files (Parquet, CSV, JSONL, audio, image), an optional loading script, and a dataset card.huggingface.co/spaces/{org}/{name}— Space repo. An app: Gradio / Streamlit / Docker / static. Has runtime config, secrets, and hardware tier.
Why the distinction matters
Every API call in huggingface_hub takes a repo_type. If you pass repo_type="model" when you mean dataset, the call returns 404 even if the repo exists — same Git infra, different namespace. The HfApi methods list_models(), list_datasets(), list_spaces() are not aliases of the same function; they hit different indices and accept different filters (e.g. task= only on models, language= on both models and datasets).
The repo type also dictates what shows up on the page: model repos get the inference widget and Use This Model button; dataset repos get the Data Studio viewer; Spaces get the running app iframe. None of that is configurable — it's bound to the repo type.