Relationships
Entity-to-entity relationships in the catalog — ERD edges from foreign keys and graph edges between graph-store nodes.
ODD Platform tracks entity-to-entity relationships as first-class catalog objects. They show up two ways: as ERD diagrams between table-class entities (foreign-key-style edges) and as graph relationships between graph-store entities (Neo4j-style edges). Both are surfaced under Data Modelling → Relationships in the UI and through the /api/relationships API.
The two relationship classes
The platform's internal model defines a DATA_RELATIONSHIP(9) data-entity class that contains two types:
ENTITY_RELATIONSHIP(25)
ERD
Foreign-key-style edges between two table-class entities. Cross-schema references are supported. The collector that catalogs the source emits one ENTITY_RELATIONSHIP per detected foreign-key constraint.
GRAPH_RELATIONSHIP(26)
GRAPH
Free-form graph edges between graph-store entities (e.g., relationships between nodes in a Neo4j database). Distinct from ERD because the cardinality model is graph-native, not relational.
A relationship is a regular catalog entity — it has an ODDRN, an owner, a namespace inherited from its source / target, and shows up in search alongside datasets. The dedicated UI surface and /api/relationships API are for list and detail navigation of just the relationship-class entities.
ERD cardinality model (ENTITY_RELATIONSHIP)
ERD relationships carry the source-and-target table pair plus a cardinality classifier. Four classifiers are defined upstream:
ONE_TO_EXACTLY_ONE— one source row maps to exactly one target row.ONE_TO_ZERO_OR_ONE— one source row maps to zero or one target row.ONE_TO_ONE_OR_MORE— one source row maps to one or more target rows.ONE_TO_ZERO_ONE_OR_MORE— one source row maps to zero, one, or many target rows.
These mirror the cardinality vocabulary defined in the odd-collectors monorepo's Relationships section.
UI walkthrough
Open Data Modelling → Relationships from the top-level navigation (/data-modelling/relationships). The list page shows every visible relationship across all data sources — as of 0.28.0 it applies the catalog's default visibility rules, so soft-deleted, hollow, and excluded-from-search relationship entities are filtered out (earlier releases listed them here even after every other catalog surface hid them). The page shows:
A table with columns Name, Type (ERD or GRAPH), Namespace + Datasource, Source entity, Target entity.
A type tab strip filtering by
ALL/ERD/GRAPH(matches the API enum).A search input filtering by name across the visible set.
Infinite-scroll pagination — page size is 30 by default.
Click a row to open the relationship's detail page; the platform routes to the /api/relationships/erd/{id} or /api/relationships/graph/{id} payload depending on the relationship type.

The same data is also surfaced per-entity — every dataset's detail page has a Relationships tab (in the same tab strip as Overview / Structure / Lineage / Test reports / Alerts / Query examples / Activity / Discussions) that lists only the relationships in which the current entity participates as Parent or Child:

The per-entity view is the operator-relevant perspective: when reading a table's documentation, you see only its incoming and outgoing relationships, not the whole catalog's. The Parent / Child columns and the cardinality glyph match the underlying ENTITY_RELATIONSHIP model and the same /api/relationships/erd/{id} payload surfaces both in this tab and on the global Data Modelling → Relationships list above. As of 0.28.0 this tab hides soft-deleted and hollow relationship entities, but — unlike the global list — it deliberately keeps exclude_from_search-flagged ones visible: that flag scopes discovery surfaces, and the dataset's own detail tab would be silently incomplete without its real relationships.
API surface
The three endpoints exposed by RelationshipController are documented at API Reference → Relationships — GET /api/relationships (paginated list with optional type=ERD|GRAPH|ALL filter and free-text query) plus the two per-type detail endpoints. The same payloads also surface on the source and target dataset's detail pages under the dataset's relationships cluster.
How relationships get into the catalog
Relationships are populated by the ingesting collector during the source-side metadata pull. The platform does not infer relationships from naming conventions or column-name similarity — only what the collector emits is surfaced.
Adapter coverage as of the time of writing (per the upstream odd-collectors Relationships matrix):
odd-collector
postgresql
ENTITY_RELATIONSHIP (ERD)
Foreign-key constraints in the database catalog. Cross-schema FKs are detected.
odd-collector
snowflake
ENTITY_RELATIONSHIP (ERD)
Foreign-key constraints in the database catalog. Cross-schema FKs are detected.
Known operator caveats
Four behaviours of the Relationships surface are non-obvious from the UI alone — they are model contracts to know about, not defects. Two further code-side defects from earlier releases (the Target-column rendering and the unvalidated ?type= parameter) were fixed in 0.28.0; the notes below describe them for operators on 0.27.x and earlier.
Where to next
Data Modelling overview — parent section; pairs Relationships with Query Examples.
Query Examples — the other Data Modelling sub-surface.
Integrations → odd-collector — the generic collector that hosts the PostgreSQL and Snowflake adapters surfacing ERD relationships today; the per-adapter feature matrix on that page calls out ERD support explicitly.
Main Concepts — for the broader catalog vocabulary that names these entities.
Last updated