Skip to content

DAG & Dependencies

Rocky builds a directed acyclic graph (DAG) from model dependencies to determine execution order. Dependencies come from two merged sources: explicit depends_on declarations in a model’s TOML, plus dependencies auto-resolved from bare table names in the model’s SQL that match another project model (surfaced as diagnostic I001). Rocky uses topological sorting over the merged set to produce a valid execution plan with parallel execution layers.

Each model declares what it depends on using the depends_on field in its TOML configuration:

name = "fct_orders"
depends_on = ["stg_orders", "dim_customers"]

This means fct_orders cannot run until both stg_orders and dim_customers have completed.

Rocky uses Kahn’s algorithm to produce a topological ordering of models. The output is deterministic: when multiple models have no remaining dependencies (i.e., they are tied), they are sorted alphabetically.

Models are grouped into layers. All models in a layer can run in parallel because their dependencies have been satisfied by earlier layers.

Example dependency graph:

stg_customers ──→ dim_customers ──┐
├──→ fct_orders
stg_orders ───────────────────────┘

This produces three execution layers:

Layer 0: stg_customers, stg_orders (no dependencies, run in parallel)
Layer 1: dim_customers (depends on stg_customers)
Layer 2: fct_orders (depends on stg_orders + dim_customers)

Rocky executes all models in Layer 0 concurrently, waits for them to finish, then executes Layer 1, and so on.

Rocky validates the DAG at rocky validate time, catching problems before any SQL is executed.

Circular dependencies are detected and reported as the set of models involved in the cycle:

model_a.toml
name = "model_a"
depends_on = ["model_b"]
# model_b.toml
name = "model_b"
depends_on = ["model_a"]
Error: DAG error: circular dependency detected involving: ["model_a", "model_b"]

References to models that don’t exist are caught:

name = "fct_orders"
depends_on = ["stg_orders", "nonexistent_model"]
Error: DAG error: unknown dependency 'nonexistent_model' referenced by 'fct_orders'

When the unknown name is a near miss for a real model, the message appends a — did you mean '<model>'? suggestion.

Not every table reference creates a dependency. Rocky classifies references based on how they are qualified in the SQL:

SQL reference Classification DAG behavior
stg_orders (matches a Rocky model) Model dependency Execution edge in DAG
stg_orders (no matching model) External reference Ignored by DAG
dbt_fivetran.stg_facebook_ads__ad_history Two-part external Ignored by DAG
analytics.dbt_fivetran.stg_facebook_ads__ad_history Three-part external Ignored by DAG

Rocky reads from external tables but does not manage, build, or schedule them.

This distinction enables hybrid workflows where Rocky models consume tables produced by other tools (dbt packages, Fivetran connectors, manual ETL) without needing to convert or import them. External tables appear in column-level lineage but are excluded from execution planning.

-- stg_orders is a Rocky model -> DAG dependency
-- dbt_fivetran.stg_facebook_ads__ad_history is external -> no dependency
SELECT
o.order_id,
f.ad_name
FROM stg_orders o
JOIN dbt_fivetran.stg_facebook_ads__ad_history f
ON o.campaign_id = f.campaign_id

See Using Rocky with dbt Packages for a full guide on this pattern.

dbt Core uses Jinja’s {{ ref('model_name') }} macro inside SQL to create implicit dependencies. The dependency graph is extracted by parsing Jinja templates:

-- dbt model
SELECT *
FROM {{ ref('stg_orders') }}
JOIN {{ ref('dim_customers') }} USING (customer_id)

Rocky uses explicit depends_on declarations in TOML:

depends_on = ["stg_orders", "dim_customers"]

The differences:

dbt Core Rocky
Declaration Implicit via {{ ref() }} in SQL Explicit depends_on in TOML + inferred from plain SQL (no templating)
When validated During parsing/compilation At rocky validate time
SQL purity SQL mixed with Jinja Pure SQL, no template language
Editor support Requires dbt LSP for ref() Standard SQL tooling works

You can run rocky validate to check the entire dependency graph without connecting to any warehouse.