Joins
Relate models with joins: relationship types, cross-source joins, fan-out protection, join paths and how Kimo suggests joins automatically.
Joins let a chart combine fields from several models: revenue by marketing channel needs orders joined to web_sessions; vessel risk by flag state needs tracks joined to a registry. Kimo declares joins in the model, not in each chart, so everyone uses the same path.
Declaring a join
joins: customers: on: orders.customer_id = customers.id relationship: many_to_one web_sessions: on: orders.session_id = web_sessions.session_id relationship: one_to_one type: leftRelationship types
| Relationship | Meaning | Fan-out risk |
|---|---|---|
many_to_one | Many orders → one customer | None (safe) |
one_to_one | One order ↔ one session | None |
one_to_many | One invoice → many lines | High: sums on invoice are inflated |
many_to_many | Campaigns ↔ contacts via a bridge | Requires a bridge model |
Joining across sources
Models from different sources can be joined as long as both are cached, or both live on the same warehouse. A typical example: Stripe subscriptions joined to HubSpot companies on a shared domain key to see MRR by account owner.
Suggested joins
Kimo inspects column names, types and value overlap to suggest joins with a match rate. Suggestions above 95% are pre-selected; anything between 70% and 95% is shown with a warning so you can check orphaned rows before accepting.
Ambiguous join paths
If two paths connect the same models (for example orders → customers directly and via subscriptions), mark one as the preferred path. Charts use it by default, and Ask Kimo explains which path it took in the answer details.
- 1Open the model graph under Models → Graph.
- 2Click the edge you want to prefer and choose Set as preferred path.
- 3Publish the model; affected tiles are listed in the review diff.
Join performance
Joins on cached models run inside Kimo’s columnar engine and are fast even across hundreds of millions of rows, as long as join keys are low-cardinality types (integers or short strings). Joins on live models are pushed down to the source when both sides live in the same database; otherwise Kimo fetches the smaller side first and filters the larger one. The query inspector (Explain on any chart) shows which strategy was used and how long each step took.
- Prefer integer keys over long text keys such as emails or URLs.
- Filter early: global dashboard filters are applied before the join when possible.
- Materialize a joined model as a derived table if the same expensive join powers many tiles.
