dbt Guide

Visualize a dbt project: the model layers, drawn from the repository

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

Every dbt visualization tool wants the same thing first: a compiled manifest.json. That means a working profile, warehouse credentials, and a successful dbt parse before anyone sees a picture. The repository already contains the answer, though. dbt_project.yml declares the layers, the folders under models/ declare the shape, and the ref calls inside the SQL declare the edges. A repo connection reads that directly.

7 min readFor analytics engineers whose project DAG only exists inside dbt docs

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

143/20003 credits left
Try:

No account needed · Editable canvas, not a picture

What the sync actually reads in a dbt repo

Datadef connects to the repository on GitHub, GitLab, or Azure DevOps with read-only access, picks a branch or tag, and walks the tree once. The classifier gives dbt_project.yml a class of its own with room for 2 files, and every .sql file under a models/ directory another with room for 12. Both sit in the data tier of the fetch order, above API specs, CI, and prose.

One distinction is worth knowing before you read the corpus: the models class is .sql under a directory named models, and nothing else. A macro, a seed, a snapshot, or a hand-written DDL file is still fetched, but through the general SQL class, which has its own ceiling of 10 and is shared with every other .sql in the repository. On a project with a large macros directory that ceiling is where the competition happens.

The target/ directory is on the skip list, along with node_modules, .venv, and the usual build output. That matters more for dbt than for most stacks: target/ holds compiled SQL that duplicates every model with the Jinja already expanded. Reading it would double the corpus and teach the model nothing new, so the sync reads your source models instead.

One honest limit: the model class matches .sql files only. The schema.yml and sources.yml files that carry descriptions and tests sit next to those models and are not part of the classified corpus, so column documentation you wrote in YAML does not reach the generator. The directory listing still shows they exist.

Corpus from a dbt repo                              cap
  dbt_project.yml            project config class        2
  models/**/*.sql            dbt model class            12   (3 under
                                                            architecture,
                                                            18 under content)
  macros/, seeds/, ddl/      general SQL class          10
  .github/workflows/*.yml    CI class                    8
  README.md                  prose class                 5

Never fetched
  target/  (skip list)   profiles.yml   *.lock   schema.yml

Layers, not one box per model

A 400-model project cannot fit in a prompt and would not read as a diagram if it did. The corpus is capped at 40 files and 250KB total, with individual files truncated past 30KB, and the model class has its own ceiling so a hundred staging models cannot crowd out the project config and the CI pipeline. Inside a class, files are ordered shallow first and then alphabetically, so models/staging/stg_orders.sql is fetched before models/marts/finance/core/fct_orders.sql.

That sampling is deliberate. What you want from a project diagram is the layer structure and the path data takes through it, not a box per model. The tree summary that rides along with the corpus lists every directory to three levels with its file count, so the generator can see that models/marts/finance holds 34 models even when only three of them were read.

On the first sync Datadef counts the classified files and proposes what the diagram should be about, in one deterministic sentence with no model call involved. A dbt repo usually reads as something like: Mostly dbt models and SQL (48 files) with 2 CI pipelines and no infrastructure code. The rule behind it is arithmetic: when the models, SQL, schemas, and API files outnumber the infrastructure, container, and CI files, the content focus is proposed. Answering content raises the model ceiling from 12 to 18 and drops infrastructure to 3; answering architecture inverts it, 3 models and 16 infrastructure files, and draws the platform around dbt instead.

Nothing runs against the warehouse

No dbt parse, no dbt run, no profiles.yml, no warehouse credentials. The connection needs read access to the repository and nothing else, which is why it works on a client project or a repo you were handed for a review. Tools built on manifest.json cannot start until someone has a working connection to Snowflake or BigQuery.

The tradeoff is stated plainly: parsing the source means the diagram shows what the project declares, not what the last run materialized. For row counts, freshness, and run status, dbt Catalog and your orchestrator already answer that question. For what the project is and how the layers connect, the source is the definition.

The generated diagram lands on a normal editable canvas, and column-to-column relationships can be drawn on it where the model detail matters. See column-level lineage for that view.

Two artifacts per sync

Each sync regenerates the diagram and an architecture doc covering the models, the data flow, and the notable directories. Both come from the same corpus, so they cannot contradict each other. See how repository sync works.

Keeping the picture current after every merge

The connected project re-syncs daily, and a sync on an unchanged commit is skipped, so a week of documentation-only commits does not redraw anything. When the branch does move, node identity is carried across the regeneration, and nodes somebody dragged by hand keep the position their owner gave them.

Put the result where people already read: one markdown image line in the repository README renders the current diagram through a live embed, with no account needed to view it. An agent in Claude Code or Cursor can also check the sync status and trigger a refresh over MCP after a modelling change merges.

FAQ

Does this need manifest.json or a dbt run?

No. The sync reads dbt_project.yml and the .sql files under models/ straight from the repository. There is no dbt parse, no dbt run, no profiles.yml, and no warehouse connection, so it works on a repository you have read access to and nothing else, including a client project or a branch that has never been built. The compiled target directory is skipped rather than read.

Will every model appear in the diagram?

Not on a large project, and that is deliberate. The corpus is capped at 40 files and 250KB, with a per-class ceiling on model files, so models are sampled shallow-first while the directory summary reports the full file count per folder. The diagram is about layers and flow rather than one box per model.

Are my schema.yml descriptions and tests used?

No. The model class matches .sql files only, so YAML documentation and test definitions next to the models are not fetched into the corpus. Descriptions you want in the diagram are better added on the canvas after generation.

Why is the compiled target directory ignored?

target/ is on the sync skip list. It contains compiled copies of the same models with Jinja already expanded, so including it would consume the file budget twice over without adding information the source did not already carry.

What is the difference between the content focus and the architecture focus here?

Content draws what the code does: sources, layers, transformations, and the path data takes to its outputs. Architecture draws the system around it: the orchestrator, containers, CI pipelines, and warehouse, sampling only a few model files for context. A dbt-heavy repo is proposed the content focus by default.