materialization lineage (2)
Rule: max_materialization_lineage
Manifest Rule
max_materialization_lineage details
This rule limits the length of consecutive non-persisted materializations in a model's lineage. It walks up the DAG via
parent_map, counting consecutive ancestors whose materialization is in the included_materializations set (default: view and ephemeral). The walk stops at non-model parents (sources, seeds, etc.) and at models with a materialization not in the included set.When a node has multiple parents (diamond patterns), the longest chain is used.
Models whose own materialization is not in the included set are skipped entirely.
Configuration
- type: Must be
max_materialization_lineage. - max: (optional) Maximum number of consecutive non-persisted models allowed in the lineage (including the current model). Defaults to
4. - included_materializations: (optional) List of materializations considered non-persisted. Only chains of these materializations are counted.
- Default:
["view", "ephemeral"] - Options:
table,view,incremental,ephemeral,materialized_view, or any custom materialization string.
- Default:
- applies_to: (optional) List of dbt object types this rule checks.
- Default:
["models"] - Options:
models
- Default:
Common Rule Config
- name: Human-readable name of the rule.
- severity:
"error"(fail) or"warning"(warn only).- (optional, defaults to
"error"if not specified)
- (optional, defaults to
- description: Human-readable explanation of the rule.
- category: Override the default rule category. Included in structured output (JSON, CSV, NDJSON) but not in the CLI table. Each rule has a built-in default (e.g.
documentation,naming,testing,governance,structure,performance).- (optional, defaults to the rule type's built-in category)
- includes: List of patterns to explicitly include for this rule. See Includes & Excludes for pattern syntax and examples.
- excludes: List of patterns to explicitly exclude from this rule. See Includes & Excludes for pattern syntax and examples.
- model_materializations: Filter models by materialization type. Only applies when
applies_toincludesmodels.- (optional, if not specified all materializations are included)
- Built-in types:
table,view,incremental,ephemeral,materialized_view. Custom materializations are also supported. - Example:
["table", "incremental"]
Example Config
manifest_tests:
- name: "no_long_view_chains"
type: "max_materialization_lineage"
max: 4
description: "Limit consecutive non-persisted materializations in lineage"
# included_materializations: ["view", "ephemeral"] (optional, default)
# severity: "warning" (optional)
# includes: ["models/marts/*"]
# excludes: ["models/staging/*"]
# Stricter limit for marts
- name: "marts_short_chains"
type: "max_materialization_lineage"
max: 2
includes: ["models/marts"]
severity: "error"[[manifest_tests]]
name = "no_long_view_chains"
type = "max_materialization_lineage"
max = 4
description = "Limit consecutive non-persisted materializations in lineage"
# included_materializations = ["view", "ephemeral"] # (optional, default)
# severity = "warning" # (optional)
# includes = ["models/marts/*"]
# excludes = ["models/staging/*"]
# Stricter limit for marts
[[manifest_tests]]
name = "marts_short_chains"
type = "max_materialization_lineage"
max = 2
includes = ["models/marts"]
severity = "error"[[tool.dbtective.manifest_tests]]
name = "no_long_view_chains"
type = "max_materialization_lineage"
max = 4
description = "Limit consecutive non-persisted materializations in lineage"
# included_materializations = ["view", "ephemeral"] # (optional, default)
# severity = "warning" # (optional)
# includes = ["models/marts/*"]
# excludes = ["models/staging/*"]
# Stricter limit for marts
[[tool.dbtective.manifest_tests]]
name = "marts_short_chains"
type = "max_materialization_lineage"
max = 2
includes = ["models/marts"]
severity = "error"Example
graph LR raw_orders["source: raw.orders"] --> stg_orders["stg_orders (view)"] stg_orders --> int_order_items["int_order_items (view)"] int_order_items --> int_orders["int_orders (view)"] int_orders --> fct_orders["fct_orders (view)"]
The rule walks up the parent_map from manifest.json. For example:
"parent_map": {
"model.project.fct_orders": ["model.project.int_orders"],
"model.project.int_orders": ["model.project.int_order_items"],
"model.project.int_order_items": ["model.project.stg_orders"],
"model.project.stg_orders": ["source.project.raw.orders"]
}With all four models materialized as view and max: 3, the fct_orders model would fail because it has a chain of 4 consecutive views (stg_orders → int_order_items → int_orders → fct_orders), which exceeds the limit of 3.
If int_orders were materialized as table, the chain at fct_orders would be just 1 (only itself), because the table breaks the chain.
Rule: exposure_parents_materialized
Manifest Rule
exposure_parents_materialized details
This rule ensures that every direct model parent of an exposure uses a persisted materialization. Exposures (dashboards, ML models, applications) that depend on non-persisted models (views, ephemeral) can suffer from poor query performance and stale data.
Only model parents are checked — sources and seeds are skipped since they don’t have configurable materializations.
One violation is produced per non-compliant parent.
Configuration
- type: Must be
exposure_parents_materialized. - allowed_materializations: (optional) List of materializations considered persisted/acceptable for exposure parents.
- Default:
["table", "incremental", "materialized_view"] - Options:
table,view,incremental,ephemeral,materialized_view, or any custom materialization string.
- Default:
- applies_to: (optional) List of dbt object types this rule checks.
- Default:
["exposures"] - Options:
exposures
- Default:
Common Rule Config
- name: Human-readable name of the rule.
- severity:
"error"(fail) or"warning"(warn only).- (optional, defaults to
"error"if not specified)
- (optional, defaults to
- description: Human-readable explanation of the rule.
- category: Override the default rule category. Included in structured output (JSON, CSV, NDJSON) but not in the CLI table. Each rule has a built-in default (e.g.
documentation,naming,testing,governance,structure,performance).- (optional, defaults to the rule type's built-in category)
- includes: List of patterns to explicitly include for this rule. See Includes & Excludes for pattern syntax and examples.
- excludes: List of patterns to explicitly exclude from this rule. See Includes & Excludes for pattern syntax and examples.
- model_materializations: Filter models by materialization type. Only applies when
applies_toincludesmodels.- (optional, if not specified all materializations are included)
- Built-in types:
table,view,incremental,ephemeral,materialized_view. Custom materializations are also supported. - Example:
["table", "incremental"]
Example Config
manifest_tests:
- name: "exposure_parents_must_be_materialized"
type: "exposure_parents_materialized"
description: "Exposure parents must use persisted materializations"
severity: "error"
# allowed_materializations: ["table", "incremental", "materialized_view"] (optional, default)
# Allow views for internal dashboards
- name: "internal_exposure_parents"
type: "exposure_parents_materialized"
allowed_materializations:
["table", "incremental", "materialized_view", "view"]
includes: ["models/internal/*"]
severity: "warning"[[manifest_tests]]
name = "exposure_parents_must_be_materialized"
type = "exposure_parents_materialized"
description = "Exposure parents must use persisted materializations"
severity = "error"
# allowed_materializations = ["table", "incremental", "materialized_view"] # (optional, default)
# Allow views for internal dashboards
[[manifest_tests]]
name = "internal_exposure_parents"
type = "exposure_parents_materialized"
allowed_materializations = ["table", "incremental", "materialized_view", "view"]
includes = ["models/internal/*"]
severity = "warning"[[tool.dbtective.manifest_tests]]
name = "exposure_parents_must_be_materialized"
type = "exposure_parents_materialized"
description = "Exposure parents must use persisted materializations"
severity = "error"
# allowed_materializations = ["table", "incremental", "materialized_view"] # (optional, default)
# Allow views for internal dashboards
[[tool.dbtective.manifest_tests]]
name = "internal_exposure_parents"
type = "exposure_parents_materialized"
allowed_materializations = ["table", "incremental", "materialized_view", "view"]
includes = ["models/internal/*"]
severity = "warning"Example exposure
Given an exposure in your dbt project:
graph LR fct_revenue["fct_revenue (table) ✅"] --> dashboard["weekly_revenue_dashboard (exposure)"] dim_dates["dim_dates (view) ❌"] --> dashboard
exposures:
- name: weekly_revenue_dashboard
type: dashboard
owner:
name: Analytics Team
depends_on:
- ref('fct_revenue')
- ref('dim_dates')If fct_revenue is materialized as table but dim_dates is materialized as view, the rule would produce one violation for dim_dates (assuming the default allowed_materializations).