code (4)

These rules inspect the raw SQL/Jinja code of your dbt resources.


Rule: code_contains_refs

Manifest Rule

code_contains_refs details
This rule checks that the raw SQL code of a resource contains at least one ref() or source() function call. It inspects the actual code text (not the dependency graph), stripping SQL comments before checking. Detection is case-insensitive.

Resources without these calls may be hardcoding warehouse table names and bypassing dbt lineage tracking. Also check out has_refs, which checks the dependency graph (depends_on.nodes) rather than the raw SQL text. It differs since has_refs also checks the depends_on config.


Configuration

  • type: Must be code_contains_refs.
  • applies_to: (optional) List of dbt object types to include.
    • Default: ["models", "snapshots"]
    • Options: models, snapshots, macros
Common Rule Config
  • name: Human-readable name of the rule.
  • severity: "error" (fail) or "warning" (warn only).
    • (optional, defaults to "error" if not specified)
  • 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_to includes models.
    • (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: "code_must_use_refs"
    type: "code_contains_refs"
    description: "All SQL code must contain ref() or source() calls."
    # severity: "warning"  (optional)
    # applies_to: ['models', 'snapshots']  (optional)
    # includes: ["models/staging/*"]
    # excludes: ["models/base/*"]
[[manifest_tests]]
name = "code_must_use_refs"
type = "code_contains_refs"
description = "All SQL code must contain ref() or source() calls."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["models/staging/*"]
# excludes = ["models/base/*"]
[[tool.dbtective.manifest_tests]]
name = "code_must_use_refs"
type = "code_contains_refs"
description = "All SQL code must contain ref() or source() calls."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["models/staging/*"]
# excludes = ["models/base/*"]
Relevant dbt code
-- models/good_model.sql (PASS - contains ref())
SELECT
    customer_id,
    first_name
FROM {{ ref('stg_customers') }}

-- models/good_source_model.sql (PASS - contains source())
SELECT *
FROM {{ source('raw', 'customers') }}

-- models/bad_model.sql (FAIL - hardcoded table name)
SELECT id, name
FROM raw_schema.users
WHERE active = true

-- models/tricky_model.sql (FAIL - ref is commented out)
-- SELECT * FROM {{ ref('stg_users') }}
SELECT id FROM raw_schema.users

Rule: has_forbidden_code

Manifest Rule

has_forbidden_code details
This rule checks if code contains forbidden patterns. Use it to enforce coding standards by flagging undesired patterns such as `SELECT *` statements, hardcoded references, or any other string patterns that should not appear in your dbt code.

Configuration

  • type: Must be has_forbidden_code.
  • forbidden_patterns: List of string patterns that are not allowed in the code. Each pattern is matched as a substring.
  • case_sensitive: (optional) Whether pattern matching should be case-sensitive. Defaults to false (case-insensitive).
  • applies_to: (optional) List of dbt object types to check.
    • Default: ["models", "snapshots", "macros"]
    • Options: models, snapshots, macros
Common Rule Config
  • name: Human-readable name of the rule.
  • severity: "error" (fail) or "warning" (warn only).
    • (optional, defaults to "error" if not specified)
  • 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_to includes models.
    • (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:
  # Forbid SELECT * in models (case-insensitive by default)
  - name: "no_select_star"
    type: "has_forbidden_code"
    forbidden_patterns: ["SELECT *"]
    description: "Models should not use SELECT *."
    # case_sensitive: false  (optional, default)
    # severity: "warning"  (optional)
    # applies_to: ['models', 'snapshots'] (optional)
    # includes: ["path/to/include/*"]
    # excludes: ["path/to/exclude/*"]

  # Case-sensitive match for exact patterns
  - name: "no_hardcoded_schema"
    type: "has_forbidden_code"
    forbidden_patterns: ["raw_prod.", "analytics_prod."]
    case_sensitive: true
    severity: "warning"
    description: "Use dbt selectors"
# Forbid SELECT * in models (case-insensitive by default)
[[manifest_tests]]
name = "no_select_star"
type = "has_forbidden_code"
forbidden_patterns = ["SELECT *"]
description = "Models should not use SELECT *."
# case_sensitive = false  # (optional, default)
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]

# Case-sensitive match for exact patterns
[[manifest_tests]]
name = "no_hardcoded_schema"
type = "has_forbidden_code"
forbidden_patterns = ["raw_prod.", "analytics_prod."]
case_sensitive = true
severity = "warning"
description = "Use dbt selectors"
# Forbid SELECT * in models (case-insensitive by default)
[[tool.dbtective.manifest_tests]]
name = "no_select_star"
type = "has_forbidden_code"
forbidden_patterns = ["SELECT *"]
description = "Models should not use SELECT *."
# case_sensitive = false  # (optional, default)
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]

# Case-sensitive match for exact patterns
[[tool.dbtective.manifest_tests]]
name = "no_hardcoded_schema"
type = "has_forbidden_code"
forbidden_patterns = ["raw_prod.", "analytics_prod."]
case_sensitive = true
severity = "warning"
description = "Use dbt selectors"
Relevant dbt code
-- models/clean_model.sql (PASS - no forbidden patterns)
SELECT
    id,
    name
FROM users
WHERE active = true

-- models/star_model.sql (FAIL - contains 'SELECT *')
SELECT * FROM users
-- Also matches: select * from users (case-insensitive by default)

Rule: max_code_lines

Manifest Rule

max_code_lines details
This rule enforces a maximum line count for dbt code objects, helping to maintain code readability and encourage modular design. Objects with empty code will also be flagged by this rule.

Configuration

  • type: Must be max_code_lines.
  • max_lines: (optional) The maximum number of lines allowed for the code. Defaults to 150.
  • applies_to: (optional) List of dbt object types to include.
    • Default: ["models", "snapshots", "macros"]
    • Options: models, snapshots, macros
Common Rule Config
  • name: Human-readable name of the rule.
  • severity: "error" (fail) or "warning" (warn only).
    • (optional, defaults to "error" if not specified)
  • 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_to includes models.
    • (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: "models_max_100_lines"
    type: "max_code_lines"
    max_lines: 100
    description: "Models should not exceed 100 lines of code."
    # severity: "warning"  (optional)
    # applies_to: ['models', 'snapshots'] (optional)
    # includes: ["path/to/include/*"]
    # excludes: ["path/to/exclude/*"]
[[manifest_tests]]
name = "models_max_100_lines"
type = "max_code_lines"
max_lines = 100
description = "Models should not exceed 100 lines of code."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]
[[tool.dbtective.manifest_tests]]
name = "models_max_100_lines"
type = "max_code_lines"
max_lines = 100
description = "Models should not exceed 100 lines of code."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]
Relevant dbt code
-- models/short_model.sql (PASS)
SELECT
    id,
    name
FROM users

-- models/very_long_model.sql (FAIL - exceeds max_lines)
SELECT
    id,
    name,
    email,
    ...
    -- 101+ lines of SQL
    ...
FROM users

-- models/empty_model.sql (FAIL - empty code)
-- No content
Use cases
  • Enforce code modularity by limiting file size
  • Prevent overly complex transformations in single files
  • Encourage breaking down large models into smaller, reusable CTEs or models
  • Maintain consistent code readability across the project
  • Catch accidentally empty SQL files

Rule: max_joins

Manifest Rule

max_joins details
This rule enforces a maximum number of JOINs in raw SQL code, helping to reduce code complexity and encourage modular design. SQL comments (single-line `--` and multi-line `/* */`) are stripped before counting, so commented-out JOINs are not counted. Detection is case-insensitive.

Configuration

  • type: Must be max_joins.
  • max_joins: (optional) The maximum number of JOINs allowed. Defaults to 5.
  • applies_to: (optional) List of dbt object types to include.
    • Default: ["models", "snapshots"]
    • Options: models, snapshots, macros
Common Rule Config
  • name: Human-readable name of the rule.
  • severity: "error" (fail) or "warning" (warn only).
    • (optional, defaults to "error" if not specified)
  • 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_to includes models.
    • (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: "limit_joins"
    type: "max_joins"
    max_joins: 3
    description: "Models should not exceed 3 JOINs."
    # severity: "warning"  (optional)
    # applies_to: ['models', 'snapshots'] (optional)
    # includes: ["path/to/include/*"]
    # excludes: ["path/to/exclude/*"]
[[manifest_tests]]
name = "limit_joins"
type = "max_joins"
max_joins = 3
description = "Models should not exceed 3 JOINs."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]
[[tool.dbtective.manifest_tests]]
name = "limit_joins"
type = "max_joins"
max_joins = 3
description = "Models should not exceed 3 JOINs."
# severity = "warning"  # (optional)
# applies_to = ["models", "snapshots"]  # (optional)
# includes = ["path/to/include/*"]
# excludes = ["path/to/exclude/*"]
Relevant dbt code
-- models/simple_model.sql (PASS - 1 JOIN, within limit of 3)
SELECT
    a.id,
    b.name
FROM {{ ref('users') }} a
JOIN {{ ref('orders') }} b ON a.id = b.user_id

-- models/complex_model.sql (FAIL - 4 JOINs, exceeds limit of 3)
SELECT a.id
FROM {{ ref('users') }} a
JOIN {{ ref('orders') }} b ON a.id = b.user_id
JOIN {{ ref('products') }} c ON b.product_id = c.id
JOIN {{ ref('categories') }} d ON c.cat_id = d.id
JOIN {{ ref('suppliers') }} e ON d.sup_id = e.id

-- models/commented_model.sql (PASS - commented JOINs are not counted)
-- JOIN old_table ON ...
/* LEFT JOIN another_table ON ... */
SELECT a.id
FROM {{ ref('users') }} a
JOIN {{ ref('orders') }} b ON a.id = b.user_id