Skip to content

doctor

dbt-forge doctor scans an existing dbt project and validates it against common best practices. Use it to catch issues before they cause production failures.

Terminal window
dbt-forge doctor [--check NAME] [--fix] [--ci] [--format FORMAT]

The command runs 11 health checks on the current dbt project and displays a summary table with pass/fail status and actionable remediation suggestions for each check.

All checks are file-based and do not require a warehouse connection.

Run a specific check only instead of all checks.

Terminal window
dbt-forge doctor --check naming-conventions
dbt-forge doctor --check test-coverage

Valid check names: naming-conventions, schema-coverage, test-coverage, hardcoded-refs, packages-pinned, source-freshness, orphaned-yml, sqlfluff-config, gitignore, disabled-models, contract-enforcement.

Auto-fix issues where possible. Currently supports two auto-fixes:

  1. Schema coverage — generates missing schema YAML stubs for undocumented models. For each model without a YAML entry, --fix creates a file at models/<layer>/_<model_name>__models.yml with a model name and description placeholder.
  2. Contract enforcement — injects config: {contract: {enforced: true}} into mart model YAML entries that are missing contract configuration.
Terminal window
dbt-forge doctor --fix

Example output:

Created models/marts/finance/_fct_revenue__models.yml
Created models/staging/stripe/_stg_stripe__orders__models.yml
Added contract enforcement to orders in _orders__models.yml
9 passed, 0 failed

Other failing checks include specific remediation hints but require manual intervention.

Non-interactive mode for CI pipelines. Exits with code 1 if any check fails, code 0 if all checks pass.

Terminal window
dbt-forge doctor --ci

Output format: table (default) or json. JSON output includes pass/fail counts and full results for each check, suitable for CI/CD integrations and dashboards.

Terminal window
dbt-forge doctor --format json

Example JSON output:

{
"passed": false,
"pass_count": 9,
"fail_count": 2,
"results": [
{
"name": "naming-conventions",
"passed": true,
"message": "All models follow naming conventions.",
"fix_hint": null
}
]
}
CheckWhat it validates
naming-conventionsStaging models prefixed stg_, intermediates prefixed int_
schema-coverageEvery SQL model has a corresponding YAML entry
test-coverageEvery model has at least one test defined
hardcoded-refsNo hardcoded database.schema.table patterns in model SQL
packages-pinnedAll entries in packages.yml have version ranges
source-freshnessSources have freshness config defined
orphaned-ymlNo YAML model entries referencing non-existent SQL files
sqlfluff-config.sqlfluff config file exists
gitignore.gitignore includes target/, dbt_packages/, logs/
disabled-modelsNo models with enabled: false (tech debt indicator)
contract-enforcementMart models have contract: { enforced: true } config

naming-conventions — Models in models/staging/ must start with stg_. Models in models/intermediate/ must start with int_. Models in other directories are not checked.

schema-coverage — Every .sql file in models/ should have a matching entry in a models: section of a YAML file. Intermediate models (int_ prefix) are excluded from this check since they are typically ephemeral and do not need schema documentation.

test-coverage — Every model should have at least one test (column-level or data test) defined in a YAML file. The check looks for data_tests: or tests: entries under model columns.

hardcoded-refs — Scans SQL files for patterns like database.schema.table that bypass ref() and source(). These break cross-environment portability.

packages-pinned — Checks that all packages in packages.yml use version ranges (version:) rather than unpinned git references.

source-freshness — Every source in *sources*.yml files should define a freshness: block with warn_after and/or error_after.

orphaned-yml — YAML model entries that reference a SQL file that does not exist. These accumulate when models are renamed or deleted without updating the YAML.

disabled-models — Models with config(enabled=false) or enabled: false in YAML. These are tech debt — either remove the model or re-enable it.

contract-enforcement — Mart-layer models (in models/marts/) should have contract: { enforced: true } in their YAML config. Data contracts ensure that downstream consumers can rely on a stable schema. Use --fix to auto-inject the contract config, or run dbt-forge contracts generate for full contract generation with column types.

The command displays a Rich table with pass/fail status per check:

dbt-forge doctor
Status Check Details
PASS naming-conventions All models follow naming conventions.
PASS schema-coverage All models have YAML documentation.
FAIL test-coverage 2 model(s) have no tests:
models/marts/finance/fct_revenue.sql
Use dbt-forge add test <model> to generate test stubs.
PASS packages-pinned All packages have version ranges.
9 passed, 2 failed

Each failing check includes the affected file paths and a specific remediation suggestion (e.g., the exact dbt-forge command to run to fix the issue).

Use --ci in CI pipelines to fail the build when checks don’t pass:

# GitHub Actions example
- name: dbt-forge doctor
run: dbt-forge doctor --ci
# GitLab CI example
doctor:
script:
- dbt-forge doctor --ci
  • Must run from inside an existing dbt project (walks up from the current directory to find dbt_project.yml).
  • Intermediate models (int_ prefix) are excluded from schema coverage checks since they are typically ephemeral.
  • The --fix flag generates missing schema stubs and injects contract enforcement config. Other fixes require manual intervention.
  • Checks are fast and do not require a warehouse connection — all data comes from local files.
  • When using --check, only the specified check runs. The exit code in --ci mode reflects only that check.