Skip to content

docs: document dbt pull primary key detection and reverse joins - #11424

Merged
MikeNitsenko merged 7 commits into
masterfrom
docs/dbt-primary-key-detection
Jul 30, 2026
Merged

docs: document dbt pull primary key detection and reverse joins#11424
MikeNitsenko merged 7 commits into
masterfrom
docs/dbt-primary-key-detection

Conversation

@MikeNitsenko

Copy link
Copy Markdown
Contributor

Updates the dbt integration page for the new primary key detection behavior in dbt pull.

  • Pull settings table — replaces the single "Auto-detect primary keys" row with the three controls that now exist: detection from unique + not_null tests (on), the column-name fallback (on), and the configurable Primary key column suffixes (_id). Adds Also generate reverse joins (off).
  • New "Primary key detection" section — documents the three-tier ladder (dbt primary_key constraints, including model-level composite blocks → strict unique + not_null tests → column-name suffixes), why only tier 1 yields composite keys, how a single column is picked (model-entity name preference, foreign keys avoided), and how to force a key from dbt.
  • What gets generated — the primary key bullet now points at that section; the joins bullet notes that dbt declares relationships in one direction only.
  • Troubleshooting — two new entries: a cube with no/wrong primary key, and a join that only works in one direction.

The old wording said keys come from "id / *_id columns and columns with a dbt primary_key constraint", which didn't mention model-level constraint blocks and implied every id-ish column gets marked — that ambiguity is what prompted the change.

🤖 Generated with Claude Code

Describe the three-tier primary key ladder (dbt constraints → strict
unique + not_null tests → column-name suffixes), the new pull options,
and add troubleshooting for missing/incorrect keys and one-directional
joins.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@MikeNitsenko
MikeNitsenko requested a review from keydunov as a code owner July 30, 2026 07:50
@github-actions github-actions Bot added the pr:community Contribution from Cube.js community members. label Jul 30, 2026
@mintlify

mintlify Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cubed3 🟢 Ready View Preview Jul 30, 2026, 7:51 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 2m 0s —— View job


Docs review — approve with 1 correctness fix; 1 medium, 3 low, 5 inline comments

Full review
  • Gather PR diff and context
  • Read docs-mintlify/docs/integrations/dbt.mdx
  • Check claims against the repo / conventions in docs-mintlify/CLAUDE.md
  • Post inline comments and summary

Overall

Good change. The old row genuinely was misleading ("Marks id / *_id columns … as the cube's primary key" implies every id-ish column gets marked), and the three-tier ladder is the right way to explain it. The prose is concrete where it matters — the strictness rule for tests (where:, severity: warn, error_if disqualify), the model-entity-name tiebreak, "a declared key is never widened or overridden by a guess". Anchors resolve (#primary-key-detection matches ### Primary key detection), the section sits in a sensible place next to #infer-column-types-from-dbt-catalog, and the two new troubleshooting accordions match the page's existing symptom-titled style. No new page, no docs.json change needed — surgical, per the docs conventions.

Note that the dbt pull implementation isn't in this OSS monorepo, so I could not verify the behavioral claims (tier order, strictness rules, entity-name preference, reverse-join type) against code. The findings below are internal-consistency and dbt-semantics issues visible from the page itself.

Findings

# Severity Location Issue
1 Medium dbt.mdx:158 "Every cube gets a primary_key" contradicts line 187 ("if a cube … ends up with no detectable key, the pull logs a warning") and the new "A generated cube has no primary key" accordion. Suggested "Every cube needs a primary_key".
2 Low dbt.mdx:153, :401 Reverse join is described as always one_to_many, but line 398 says the forward type can be one_to_one too — in which case the inverse isn't one_to_many.
3 Low dbt.mdx:178-184 The composite-key snippet has no contract: enforced: true. dbt normally requires a model contract for constraints: to be honored — either the snippet needs it, or the page should say Cube reads constraints from the manifest regardless. This is the sample readers will copy verbatim.
4 Low dbt.mdx:162 "regardless of the two options below" — the options are in the table above this section.
5 Nit dbt.mdx:149 "Only shown when the option above is on" is positional; the reverse-joins row you added names its parent explicitly. Worth matching.

Smaller points, not worth inline threads

  • "Cube looks for it in three tiers" / "Cube prefers the one named after the model" — the rest of the page consistently attributes pull-time behavior to "the pull" or "dbt pull" and reserves "Cube" for the product ("Cube requires one on both ends of every join", two sentences earlier). Using both in one paragraph blurs the two.
  • "with layer prefixes (stg_, dim_, fct_, …) stripped and plurals reduced" — "plurals reduced" is doing a lot of work; the stg_customers → customer_id example carries it, so this may be fine as-is.
  • The "only tier 1 yields composite keys" point is stated three times (section body, troubleshooting accordion, and implicitly in "What gets generated"). Defensible — troubleshooting is a separate entry point — but docs-mintlify/CLAUDE.md asks you to say it once, so consider trimming the accordion bullet to a pointer.
  • The Limitations section wasn't touched. "Single-column keys unless dbt declares a composite constraint" is arguably a limitation worth a bullet there, but the new section covers it and the page is already long — your call.

Not applicable

Security, performance, and test-coverage checks don't apply — this is a single .mdx content change with no code, no user input handling, and no build-affecting edits. docs.json needs no update (no new page). Mintlify components used (<Accordion>, tables, fenced yaml) all match existing usage on the page. I did not run the Mintlify dev server; the preview deployment above is already green.

· Branch `docs/dbt-primary-key-detection`

Comment thread docs-mintlify/docs/integrations/dbt.mdx
Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
Comment thread docs-mintlify/docs/integrations/dbt.mdx
Comment thread docs-mintlify/docs/integrations/dbt.mdx
Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
@mintlify

mintlify Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cubed3 🟡 Building Jul 30, 2026, 7:50 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

- "Every cube needs a primary_key" — a cube can end up without one
- constraints snippet now includes the enforced model contract dbt
  requires, plus a pointer to the test-based path for projects without
  contracts
- name the parent option instead of "the option above"/"below"
- attribute pull-time behavior to "the pull", not "Cube"

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 2m 14s —— View job


Re-review of ab5d7bc — 4 of 5 prior threads addressed and resolved; 1 low finding remains

Full review
  • Diff the follow-up commit against the first push
  • Re-read the changed section of dbt.mdx
  • Resolve stale review threads
  • Post remaining findings

What the follow-up fixed

Prior finding Status
"Every cube gets a primary_key" contradicted the warning at the end of the section Fixed — now "needs a primary_key", and "The pull looks for it in three tiers"
"regardless of the two options below" pointed the wrong way Fixed — "even when both detection options are off"
"Only shown when the option above is on" was positional Fixed — names Auto-detect primary keys from column names
The composite-key snippet had no model contract Fixed — snippet now carries config.contract.enforced plus the data_type entries dbt requires, with a link to dbt's contract reference, and a fallback sentence for projects that don't use contracts
"Cube looks for it" / "Cube prefers" blurred product vs. pull-time behavior (smaller point) Fixed — both now read "the pull"
Only-tier-1-yields-composite-keys stated three times (smaller point) Fixed — the troubleshooting bullet is trimmed to "declare the key in dbt and the pull will use it verbatim"

Those four threads are resolved. The contract link (https://docs.getdbt.com/reference/resource-configs/contract) and both claims around it — constraints need an enforced contract, an enforced contract needs data_type on every column — match dbt's documented behavior.

Remaining

Low — reverse join type is still hardcoded (dbt.mdx:153, :414). The direction wording improved, but the type didn't: line 412 says the forward relationship can be one_to_one, whose inverse is one_to_one, not one_to_many. Left the thread open with a suggestion — if the emitter always writes one_to_many regardless of the forward type, the current text is correct as-is and the thread can just be closed.

Question, not a blocker. The snippet now shows the enforced-contract path, which is right for a reader authoring constraints in dbt. Worth confirming whether Cube's tier 1 actually requires enforcement, or whether it reads constraints out of manifest.json regardless — dbt parses constraint blocks into the manifest even when it warns about the missing contract. If the latter, the current phrasing over-prescribes slightly for readers who don't want contracts (though the tier-2 fallback sentence softens that). Also still unverified: whether composite column order is preserved as written ([account_sk, valid_from]), since that affects join semantics.

Scope

As before, the dbt pull implementation isn't in this OSS monorepo, so the behavioral claims (tier order, strictness rules, entity-name preference, reverse-join type, constraint ordering) can't be checked against code — the findings above are internal-consistency and dbt-semantics issues visible from the page. Security, performance, and test-coverage checks don't apply to a single .mdx content change; docs.json needs no update (no new page); anchors and <Accordion> usage match the rest of the page. The Mintlify preview deployment is green.

· Branch `docs/dbt-primary-key-detection`

Comment thread docs-mintlify/docs/integrations/dbt.mdx
Generated joins are always many_to_one from the cube owning the foreign
key; one_to_many/one_to_one were never emitted for forward joins.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 45s —— View job


Re-review of 0210d31 — all threads resolved, no remaining findings

Full review
  • Diff 0210d31 against the previous push
  • Re-read the pull-settings table, the new section, and "What gets generated"
  • Check the join-type claims for internal consistency across the page
  • Resolve the last open thread

What changed

0210d31 rewrites the joins bullet in What gets generated:

  • Drops the inaccurate "with the relationship type (many_to_one, one_to_many, or one_to_one) inferred from the models".
  • Replaces it with the mechanism — the FK column lives on the "many" side, so every generated join is many_to_one from the cube that owns it.

That's the right fix, and it's better than what I suggested: naming the actual invariant beats hedging with "usually". Your explanation of why also stands up on the page's own terms — a relationships test is declared on the model holding the FK, so there is only one direction to emit and no type to infer.

Consistency check

Every mention of a relationship type now lines up:

Location Claim
dbt.mdx:153 reverse join adds one_to_many back to the referencing cube
dbt.mdx:412-414 forward join is always many_to_one from the FK owner
dbt.mdx:414-416 reverse join emits one_to_many

No contradiction remains, so the type is safe to name concretely in both spots rather than describing it as an inverse. I resolved my thread on line 153 — its premise (a forward type that varies) doesn't hold.

Also verified after the earlier round: the #primary-key-detection anchor still resolves from both the settings table and the troubleshooting accordion; the composite-key snippet carries config.contract.enforced with data_type on both columns and the no-contracts fallback sentence; both new accordions match the page's symptom-titled style. No docs.json change needed.

Remaining

Nothing blocking, and nothing worth a new thread. The only optional item left from the first round is the untouched Limitations section — "single-column keys unless dbt declares a composite constraint" could be a bullet there, but the new section already covers it and the page is long. Your call.

Scope

The dbt pull implementation isn't in this OSS monorepo, so I took your source reads (forward always many_to_one, reverse always one_to_many, column order carries no meaning) as given — I could only check internal consistency and dbt semantics from the page. Security, performance, and test-coverage checks don't apply to a single .mdx content change. The Mintlify preview deployment is green.

Looks good to merge.

· Branch docs/dbt-primary-key-detection ·

Verified the page against the implementation: document that join target
columns are keyed regardless of the tiers, that a primary_key constraint
naming an undocumented column is skipped entirely, and that foreign-key
avoidance is a preference with a fallback. Order the pull options to
match the settings card.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 1m 40s —— View job


Re-review of e4f535d — 1 medium, 1 nit; no prior threads to reopen

Full review
  • Diff the new commit against the previous push
  • Re-read the changed sections of dbt.mdx
  • Check internal consistency and dbt semantics
  • Resolve stale threads and post findings

What changed

e4f535d adds three things and reorders one:

Change Assessment
Join target columns are always keyed on the target cube (:177-178) Genuinely new information, and the "Cube can't resolve the join otherwise" justification is the right one-liner. But it interacts badly with two existing sentences — see below.
FK avoidance softened from "avoids" to "deprioritizes … unless that would leave no candidate" (:174-176) Good correction. The 1:1 satellite parenthetical earns its space — it's the case a reader would otherwise file as a bug.
Constraints are all-or-nothing when a column isn't documented (:700-703) Strong troubleshooting entry. "Rather than emitting a narrower, wrong grain" explains why it's skipped, which is what makes the behavior non-surprising.
Settings table reordered to match the UI card (:147-149) Fine. The tests row now sits below the column-name rows, i.e. tier 3 above tier 2 — but "Outranks the column-name guess" was added to that row, which covers it, and the suffixes row stays adjacent to the parent it depends on. Matching the UI is the better tradeoff.

Findings

Medium — dbt.mdx:177-178. "A column that another cube joins to is always marked as a key on the target cube" is unconditional, and two nearby sentences assume it isn't:

  • Line 204, "a declared key is never widened or overridden by a guess" — if a cube declares primary_key: [account_sk] and another cube joins to legacy_id, keying legacy_id too is widening the declared key.
  • Line 204–205 and the "No key at all" troubleshooting bullet (:697) — if join targets are always keyed, a cube involved in a join can't end up keyless, so that warning only ever fires for cubes with no joins.

Both readings (join-target marking as fallback vs. additive on top of a declared key) are supportable from the text, and they produce different grains. One clause naming the precedence resolves it. Inline thread posted.

Nit — dbt.mdx:703, :705. Both new bullets point at "the pull log", but the page never says where that is — the only pull output it describes is the progress toast at line 322. Line 205 leans on log output too. In a troubleshooting accordion that's the actionable half. Inline thread posted.

Thread hygiene

All six prior threads on this PR are resolved and none of their concerns resurface in this commit — nothing to reopen, nothing to re-affirm. The two threads above are new lines with new root causes, so no dedup conflict.

Consistency re-check

The join-type story from 0210d31 is untouched and still lines up (:153 reverse one_to_many, :414-418 forward always many_to_one from the FK owner). The #primary-key-detection anchor still resolves from the settings table (:147) and both troubleshooting exits (:697, :709). The composite-key snippet still carries config.contract.enforced with data_type on both columns and the no-contracts fallback. No docs.json change needed — no new page.

Scope

The dbt pull implementation isn't in this OSS monorepo, so the behavioral claims this commit adds (join-target keying, all-or-nothing constraints, FK-deprioritization fallback, what the log emits) can't be checked against code — I took your source reads as given and checked internal consistency and dbt semantics from the page. Security, performance, and test-coverage checks don't apply to a single .mdx content change. The Mintlify preview deployment is green.

Neither finding blocks merge; the medium one is worth a sentence before you do.

· Branch docs/dbt-primary-key-detection ·

Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
Join-referenced columns are additive on top of the tiers and apply to
the referenced cube only, so the FK owner is what typically ends up
keyless. Replace pointers to pull log output, which isn't surfaced to
users, with the compile error and the generated .yml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 1m 24s —— View job


Re-review of 103ea6d — 1 low finding; both prior threads addressed, all threads resolved

Full review
  • Diff 103ea6d against the previous push
  • Re-read the primary key detection section and the troubleshooting accordion
  • Check the new compile-error claim against this repo
  • Check thread state and deduplicate

What the commit fixed

Prior finding Status
"A column that another cube joins to is always marked as a key" collided with "never widened by a guess" and the keyless-cube warning Fixed. The paragraph now says the marking is additive, lands on the referenced cube, and that the FK owner gets nothing from it — "which is the usual reason a cube in a join ends up without one". That closes the loop I couldn't close from the text: my second inference (a cube in a join can't be keyless) was wrong for the reason you gave, and the page now states it. Line 208 was reworded to match — "never overridden or widened by the guessing tiers — only a joined-to column can add to it".
Three bullets pointed at a "pull log" the page never located Fixed, and better than a pointer. Since the warnings only reach server-side observability, removing them was the right call: the keyless case now names the compile error users actually hit, the ignored-constraint bullet says what to check in the dbt YAML, and the accordion closes on the generated .ymlprimary_key: true on a dimension is something a reader can actually go look at.

Both threads resolved. All eight threads on this PR are now resolved; nothing to reopen and no dedup conflict with the finding below (new lines, new root cause).

Finding

Low — dbt.mdx:208-212, the compile-error claim is unconditional. This is the one new claim I could verify against this repo, and it's almost right. JoinGraph.buildJoinEdges (packages/cubejs-schema-compiler/src/compiler/JoinGraph.ts:135-143) only reports primary key for '<cube>' is required… when the keyless cube has a multiplied measure — count, sum, avg, or number. With Add default measures on (the default) every generated cube carries a count, so "the data model won't compile" holds. With it off, no error fires and the join edge is dropped silently — the worse symptom, because nothing surfaces it. A half-clause covers it.

Also: the quoted string is a prefix. The full message ends …in order to make aggregates work properly. Searchable either way, but an would signal truncation. Inline thread posted.

Consistency re-check

  • The additive rule at :177-182 and "only a joined-to column can add to it" at :208 now agree, and both agree with the keyless-cube case at :704.
  • The join-type story from 0210d31 is untouched and still lines up (:153 reverse one_to_many, forward always many_to_one from the FK owner).
  • #primary-key-detection still resolves from :147 and :715. Composite-key snippet still carries config.contract.enforced with data_type on both columns plus the no-contracts fallback. Both accordions keep the page's symptom-titled style. No docs.json change needed — no new page.
  • The inline code span at :210-211 wraps across a newline; Markdown collapses that to a space, so it renders as one line. Fine.

Scope

The dbt pull implementation isn't in this OSS monorepo, so its behavioral claims (additive join-target keying, all-or-nothing constraints, tier order, FK deprioritization) rest on your source reads — I checked internal consistency and dbt semantics from the page. The one claim that does touch this repo, the compile error, I verified in JoinGraph.ts; hence the finding above. Security, performance, and test-coverage checks don't apply to a single .mdx content change. The Mintlify preview deployment is green.

The finding doesn't block merge — it's a qualifier on a sentence that's correct under default settings.

· Branch docs/dbt-primary-key-detection ·

Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
The compile error only fires when the cube has an aggregatable measure;
without one the join is dropped with no error. Quote the full message.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 1m 14s —— View job


Re-review of 5ade1ef — prior thread addressed and resolved; 1 low finding

Full review
  • Diff 5ade1ef against the previous push
  • Verify the two-case claim against JoinGraph.ts
  • Check thread state and dedupe
  • Post findings

What the commit fixed

The single open thread from the last round — the unconditional compile-error claim and the truncated error string — is addressed, and the split into two cases is better than the half-clause I suggested. The outcomes genuinely differ (hard failure vs. a join that quietly stops existing), so they deserve separate bullets. Verified against the source:

Claim Check
Error only fires when the keyless cube has an aggregatable measure Confirmed — JoinGraph.ts:135-143, guard is !primaryKeys[cube].length && multipliedMeasures.length > 0, and it's applied to both the from and to cube, so "a cube that participates in a join" is the right scope
Add default measures puts a qualifying count on every cube Confirmed — count is in the type list at :117-122, and the settings row at :150 says the option adds one to every cube
Without one, the join is dropped Confirmed — the guard return falses out of the .filter, so the edge never reaches the graph
Full error message Matches JoinGraph.ts:126 verbatim

Thread resolved. All nine threads on this PR are now resolved; the finding below is on new lines with a different root cause, so no dedup conflict.

Finding

Low — dbt.mdx:215-216, the no-measure case isn't silent, it's deferred. "There's no error" holds at compile time, but once the edge is dropped, a query touching both cubes reaches buildJoin and throws Can't find join path to join '<cube>', '<cube>' (JoinGraph.ts:196). The reader does get a message — later, and phrased as a missing join path rather than a missing key, which is precisely why it's hard to trace back to this section. Naming that string makes the bullet searchable the same way the compile error above it is.

Same thread, secondary: "aggregatable measures" is a touch wider than getMultipliedMeasures, which matches sum / avg / count / number (plus raw count(*) sql) — min and max are aggregates that don't trigger the guard. Immaterial with Add default measures on; only bites someone who turned it off and expected their max measure to surface the problem.

Consistency re-check

Nothing else moved. The additive join-target rule at :177-182 still agrees with "only a joined-to column can add to it" at :208; the join-type story from 0210d31 is untouched (:153 reverse one_to_many, forward always many_to_one from the FK owner); #primary-key-detection still resolves from the settings table and both troubleshooting exits; the composite-key snippet still carries config.contract.enforced with data_type on both columns plus the no-contracts fallback. No docs.json change needed — no new page.

Scope

The dbt pull implementation isn't in this OSS monorepo, so its behavioral claims (tier order, additive join-target keying, all-or-nothing constraints, FK deprioritization) rest on your source reads. Everything this commit touches that does land in this repo — the guard condition, the measure types, the error text — I checked in JoinGraph.ts. Security, performance, and test-coverage checks don't apply to a single .mdx content change. The Mintlify preview deployment is green.

The finding doesn't block merge; the sentence is correct as far as compile time goes.

· Branch docs/dbt-primary-key-detection ·

Comment thread docs-mintlify/docs/integrations/dbt.mdx Outdated
- name the measure types that trigger the compile error, and the
  runtime "Can't find join path" failure when none is present
- drop the unqualified "Cube requires a key on both ends of every join"
- Limitations no longer claims tests are unused; they feed key and join
  detection
- note that warehouse enforcement is irrelevant (the pull only parses)
- a dbt relationship describes one side, rather than dbt being unable to
  declare both

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 1m 42s —— View job


Re-review of d73280f — prior thread addressed and resolved; 1 nit, nothing blocking

Full review
  • Diff d73280f against the previous push
  • Re-read the changed sections of dbt.mdx
  • Verify the runtime-error string and measure types against JoinGraph.ts
  • Check thread state, dedupe, resolve stale threads
  • Post findings

What the commit fixed

The one open thread — the no-measure bullet claiming "there's no error", and "aggregatable measures" being wider than the guard — is addressed, and the sweep you did beyond it is the right instinct. Verified everything this commit touches that lands in this repo:

Claim Check
count, sum, avg, number are the qualifying types Confirmed — JoinGraph.ts:117-122, ['sum','avg','count','number'] plus a bare count(*) sql measure. min/max correctly excluded now
Compile error text Verbatim match with joinRequired at :126-127
Runtime message Can't find join path to join '<cube>', '<cube>' Confirmed — :196 builds it as `Can't find join path to join ${cubesToJoin.map(v => `'${v}'`).join(', ')}`, so the quoting and comma in your rendering are exact
"depends on the cube's measures" scopes to the keyless cube Confirmed — the guard pairs primaryKeys[X] with getMultipliedMeasures(X) for the same cube, and runs on both the from and to side

Thread resolved. All ten threads on this PR are now resolved.

The other four sweeps hold up on the page's own terms:

  • Section opener — "Cube relies on it to aggregate correctly across joins" replaces the flat "requires one on both ends", which the two-case passage below had just contradicted. Now the opener and the detail agree.
  • Limitations / tests — the old bullet said tests aren't imported, which this PR falsified. "Read as evidence, not converted" is the accurate distinction, and it links back to the new section.
  • One-directional relationships — "a dbt relationship describes the reference from the referencing side only" is the correct weaker claim; a project can write relationships on both models, and that would produce two forward joins rather than a reverse one.
  • Contract snippet — the # …every other column of the model needs a data_type too comment closes the one way the sample could mislead, since an enforced contract fails on any undocumented column.

Finding

Nit — dbt.mdx:206-207. "The pull only runs dbt parse" is stronger than the page's own framing 160 lines up: line 44–49 says "By default, no connection to your data warehouse is made… The one exception is [Infer column types from dbt catalog]", and line 237 confirms that option "additionally runs dbt docs generate". The load-bearing half of the new sentence is the first one (your warehouse doesn't need to enforce keys); the mechanism half both over-claims and repeats the intro. Suggested trim posted inline.

Consistency re-check

  • Join-type story unchanged and still aligned: :153 reverse one_to_many, :434-440 forward always many_to_one from the FK owner.
  • The additive join-target rule at :177-182 still agrees with "only a joined-to column can add to it" at :213, and with the keyless-cube case at :706.
  • #primary-key-detection resolves from the settings table (:147), "What gets generated" (:433), the new Limitations bullet (:618), and the troubleshooting accordion (:722). All other in-page anchors intact.
  • Both accordions keep the page's symptom-titled style; <AccordionGroup>/<Accordion>/<Note>/<Warning> tags balance. No docs.json change needed — no new page.

Scope

The dbt pull implementation isn't in this OSS monorepo, so its behavioral claims (tier order, additive join-target keying, all-or-nothing constraints, FK deprioritization, reverse-join type) rest on your source reads — I checked internal consistency and dbt semantics from the page. Everything touching this repo I verified in JoinGraph.ts, per the table above. Security, performance, and test-coverage checks don't apply to a single .mdx content change. The Mintlify preview deployment is green.

Looks good to merge; the nit is optional.

· Branch [`docs/dbt-primary-key-detection`](https://github.com/cube-js/cube/tree/docs/dbt-primary-key-detection)

Comment thread docs-mintlify/docs/integrations/dbt.mdx
@MikeNitsenko
MikeNitsenko merged commit e222415 into master Jul 30, 2026
27 checks passed
@MikeNitsenko
MikeNitsenko deleted the docs/dbt-primary-key-detection branch July 30, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:community Contribution from Cube.js community members.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant