Skip to main content

dbt-arch-unit

CI License: MIT Python 3.10+ PyPI Ruff

Architectural unit testing for dbt projects.

Like ArchUnit for Java or import-linter for Python — but for dbt. Declare the architecture your team already agreed on in a single dbt_arch.yaml, and enforce it in CI and pre-commit.

# dbt_arch.yaml  (next to dbt_project.yml)
layers:
  staging:   { paths: ["models/staging/**"],   prefixes: ["stg_"] }
  marts:     { paths: ["models/marts/**"],      prefixes: ["fct_", "dim_"] }
  reporting: { paths: ["models/reporting/**"],  prefixes: ["rpt_"] }

rules:
  - name: expect-dependencies
    # Flow chains: data moves left -> right, so "a > b" lets b depend on a.
    # Adjacent only — list a skip ("staging > reporting") or same-layer ("marts > marts") explicitly.
    allow: ["source > staging > marts > reporting", "marts > marts"]
    deny: []   # blacklist edges; deny always wins over allow
  - name: expect-max-lines-of-code
    max: 200
  - name: expect-primary-key
    scope: [marts]          # run this test only on the marts layer
  - name: expect-no-select-star
    ignore: [staging]       # run everywhere except staging
  - name: expect-model-name-convention
    case: snake_case        # or kebab-case / camelCase; also max_length / prefix / suffix
  - name: expect-comments
    forbid: ["TODO", "FIXME"]   # allowed: true by default; also max_length / allow_block
  - name: expect-min-tests-per-model    # every model needs ≥ N data tests (min:1 = "has any")
    min: 1
  - name: expect-min-tests-per-source   # every source needs ≥ N data tests
    min: 1
  - name: expect-max-models-per-layer
    max: 20
    scope: [reporting]           # keep certain layers intentionally small

Every rule accepts scope: [layers] (run only on these layers) and ignore: [layers] (run everywhere except these) — layer-based selectors, distinct from the path-glob include: / exclude:. Rule params like max are written inline; the older config: { max: 200 } form still works.

# after `dbt parse` (produces target/manifest.json)
dbt-arch-unit check          # run all configured rules, exit 1 on violations
dbt-arch-unit check --json   # machine-readable output for CI
dbt-arch-unit report -o report.html --open   # full HTML report + open it
dbt-arch-unit list-rules     # every available rule
dbt-arch-unit explain expect-dependencies
dbt-arch-unit init           # validate this is a dbt project, then scaffold config

Installation

Requires Python 3.10+.

# once published to PyPI:
pip install dbt-arch-unit
pipx install dbt-arch-unit          # isolated CLI install
uv tool install dbt-arch-unit       # via uv

# from source (available today):
uv tool install git+https://github.com/dardanxh/dbt-arch-unit
pipx install git+https://github.com/dardanxh/dbt-arch-unit

# for local development:
git clone https://github.com/dardanxh/dbt-arch-unit
cd dbt-arch-unit
uv sync --extra dev
uv run dbt-arch-unit --help

Use as a pre-commit hook

Add to your dbt project's .pre-commit-config.yaml:

repos:
  - repo: https://github.com/dardanxh/dbt-arch-unit
    rev: v0.1.0
    hooks:
      - id: dbt-arch-unit

Severity & CI

Every rule has a severity — error (default) or warning. Set it per rule, or change the project-wide default:

defaults:
  severity: error          # applied to any rule that doesn't set its own

rules:
  - name: expect-no-select-star        # error (inherits the default)
  - name: expect-min-tests-per-model
    severity: warning                # reported, but never fails CI

dbt-arch-unit check exits 1 if there is at least one error-severity violation, and 0 otherwise — warnings alone never fail the job. Run it in CI right after dbt parse:

# .github/workflows/ci.yml
- run: dbt parse                 # produces target/manifest.json
- run: dbt-arch-unit check       # non-zero exit on any error -> job fails

Use dbt-arch-unit check --warn-only to always exit 0 (report without failing).

How it works

Hybrid parsing: target/manifest.json supplies the accurate dependency graph, configs, tags, columns and tests; raw .sql/.yml files supply line counts, CTE structure, select * usage and joins. Each rule is a small, self-contained function. See dbt-arch-unit list-rules for the full catalog.

init — guarded scaffolding

dbt-arch-unit init first checks that the target directory is actually a dbt project before writing anything:

  • dbt_project.yml exists and parses, and declares a name (required),
  • the model-paths directory exists (required),
  • it contains .sql models and a compiled target/manifest.json (advisory).

If the required checks fail, no file is written and it exits non-zero. On success it auto-detects your models/ layer folders (staging, intermediate, marts, reporting, …) and writes a dbt_arch.yaml tailored to them.

dbt-arch-unit init                          # inspect ./ and scaffold
dbt-arch-unit init --project-dir path/to/dbt
dbt-arch-unit init --force                  # overwrite an existing config

HTML report

dbt-arch-unit report runs the checks and writes a single, self-contained .html file (no external assets) with:

  • a pass/fail banner and headline stats (total issues, errors, warnings),
  • percentages — % of models affected and % of rules passing,
  • bar-chart breakdowns of issues by category, by rule, and by severity,
  • the full findings table (severity, rule, location, message).
dbt-arch-unit report -o architecture_report.html          # write the report
dbt-arch-unit report -o report.html --open                # and open it
dbt-arch-unit check --html report.html                    # table + report in one go

Rule catalog

41 rules across six categories — dependencies, naming, testing, documentation, style, and materialization governance. Run dbt-arch-unit list-rules to see them all, or dbt-arch-unit explain <rule> for details and config keys.

Contributing

Contributions are very welcome — especially new rules. See CONTRIBUTING.md for the dev setup and a walkthrough of adding a rule, and please follow the Code of Conduct.

License

MIT © Dardan Xhymshiti

Metadata

Release files for dbt-arch-unit 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dbt-arch-unit 1.0.0
File Size Uploaded
dbt_arch_unit-1.0.0.tar.gz 96.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dbt-arch-unit 1.0.0
File Interpreter ABI Platform
dbt_arch_unit-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 134.3 kB

Release files / dbt_arch_unit-1.0.0.tar.gz

Download URL dbt_arch_unit-1.0.0.tar.gz
Size 96.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f72d95569c8ba51b5c0cc860a5b8b01b9c4dcdece0900c75ecf2fc73111dbde1
BLAKE2b-256 checksum
How to use checksums
3e50a35ed3cd341b69897f0b44b7a36e47f2b88af6334360d54d1e3d53ec308b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release files / dbt_arch_unit-1.0.0-py3-none-any.whl

Download URL dbt_arch_unit-1.0.0-py3-none-any.whl
Size 37.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ea8ca2ec79185c67c5a21d712a600619f354e67c1fbec756c71c26ae32858bf
BLAKE2b-256 checksum
How to use checksums
e83ff91a78eda5b50be18fbc538f5f6e4fb25cc0720f1aed80cf0416718389c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page