kimo

Joins

Relate models with joins: relationship types, cross-source joins, fan-out protection, join paths and how Kimo suggests joins automatically.

Updated Sep 22, 20265 min readEdit on GitHub

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: left

Relationship types

RelationshipMeaningFan-out risk
many_to_oneMany orders → one customerNone (safe)
one_to_oneOne order ↔ one sessionNone
one_to_manyOne invoice → many linesHigh: sums on invoice are inflated
many_to_manyCampaigns ↔ contacts via a bridgeRequires 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.

Stripe × HubSpot × Postgres is the most common cross-source combination in Kimo Business Intelligence.

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.

  1. 1Open the model graph under Models → Graph.
  2. 2Click the edge you want to prefer and choose Set as preferred path.
  3. 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.