dbt Artifacts Explained: manifest.json, run_results.json, and More
Every time dbt compiles, runs, tests, or generates documentation, it writes structured JSON files to the target/ directory describing exactly what it did. These artifacts are the machine-readable layer underneath everything covered so far in this series โ the documentation site, the lineage graph, and increasingly, external tooling that integrates with dbt without needing to parse SQL directly.
The Core Artifacts and What Each One Contains
| Artifact | Produced by | Contains |
|---|---|---|
manifest.json | compile, run, docs generate, most commands | Full project structure: models, sources, tests, macros, dependencies, configuration |
run_results.json | run, test, build, seed, snapshot | Per-node execution results: status, timing, rows affected, compiled SQL |
catalog.json | docs generate | Actual warehouse metadata: column names, types, table statistics |
sources.json | source freshness | Freshness check results per source table |
Each is a plain JSON file, human-readable if you open one directly, but really designed to be consumed programmatically.
manifest.json: The Projectโs Full Blueprint
This is the most information-dense artifact โ a complete representation of every node in your project and how they connect.
dbt compilecat target/manifest.json | jq '.nodes | keys' | head -5[ "model.my_project.stg_orders", "model.my_project.stg_customers", "model.my_project.customer_orders", "test.my_project.unique_stg_orders_order_id", "source.my_project.raw.orders"]Any tool that needs to understand your dbt projectโs structure without parsing SQL directly โ a custom internal dashboard, a lineage visualization tool, a CI script checking for orphaned models โ reads manifest.json rather than trying to reimplement dbtโs own dependency parsing.
run_results.json: What Actually Happened
While manifest.json describes structure, run_results.json describes outcomes โ what ran, whether it succeeded, how long it took.
dbt runcat target/run_results.json | jq '.results[] | {unique_id, status, execution_time}'{"unique_id": "model.my_project.stg_orders", "status": "success", "execution_time": 1.24}{"unique_id": "test.my_project.unique_stg_orders_order_id", "status": "fail", "execution_time": 0.41}This is the artifact most orchestration integrations care about most โ itโs exactly what tells an Airflow DAG or a monitoring dashboard whether the run actually succeeded and where time was spent, covered in more depth in Artifacts in Orchestration.
catalog.json: What the Warehouse Actually Has
Unlike manifest.json, which describes what dbt intends to build, catalog.json reflects what actually exists in the warehouse after a build โ real column types, real row counts where the adapter supports it.
dbt docs generatecat target/catalog.json | jq '.nodes["model.my_project.stg_orders"].columns'This distinction matters when debugging a mismatch between what a modelโs YAML claims about a column and what actually landed in the warehouse โ catalog.json is ground truth, manifest.json is intent.
Using Artifacts to Build Custom Tooling
Because artifacts are just JSON, teams commonly build lightweight internal tools directly against them rather than waiting for a feature to appear in dbt itself.
import json
with open("target/manifest.json") as f: manifest = json.load(f)
# Find every model with zero tests attached โ a data quality audituntested_models = [ node_id for node_id, node in manifest["nodes"].items() if node["resource_type"] == "model" and len(node.get("columns", {})) > 0 and not any(manifest["nodes"].get(f"test.{node_id.split('.', 2)[2]}"))]This kind of script โ scanning manifest.json for models lacking test coverage, then surfacing that as a report โ is a common internal tool teams build to enforce testing standards without manually auditing every model file.
Comparing Artifacts Across Runs
Since artifacts are timestamped JSON snapshots, comparing two runsโ run_results.json files is a straightforward way to detect regressions โ a model that used to take 2 seconds now taking 45 is visible immediately as a diff between two artifact files, without needing a dedicated performance monitoring tool.
# Simplified comparison conceptdiff <(jq '.results[] | .execution_time' old_run_results.json) \ <(jq '.results[] | .execution_time' new_run_results.json)Artifact Schema Versioning
Artifacts include a dbt_schema_version field, and the schema does change between dbt versions โ any tooling built against these files should check the schema version rather than assuming a fixed structure indefinitely, since a dbt upgrade can restructure fields in ways that silently break a script relying on an undocumented, version-specific shape.
{ "metadata": { "dbt_schema_version": "https://schemas.getdbt.com/dbt/manifest/v12.json" }}sources.json in Detail
Worth a closer look on its own: sources.json is produced specifically by dbt source freshness and captures, per source table, the exact freshness status along with the timestamps used to compute it.
{ "results": [ { "unique_id": "source.my_project.raw.orders", "status": "pass", "max_loaded_at": "2026-07-04T08:12:00Z", "snapshotted_at": "2026-07-04T09:00:00Z", "max_loaded_at_time_ago_in_s": 2880 } ]}This structure is what makes programmatic freshness-gated orchestration possible, as covered in Artifacts in Orchestration โ a script can check max_loaded_at_time_ago_in_s directly rather than re-implementing freshness logic independently of what dbt already computed.
Common Mistakes
Parsing artifacts without checking the schema version. A script that worked fine against dbt 1.5โs manifest structure can silently break after upgrading to a newer version with restructured fields.
Committing target/ to version control. Artifacts are generated output, not source โ they belong in .gitignore, regenerated fresh by CI/CD rather than tracked as committed files.
Building custom tooling against run_results.json without also checking manifest.json. Execution results alone donโt tell you why something ran or how it depends on other nodes โ the two artifacts are usually needed together for anything beyond simple pass/fail reporting.
Summary
| Artifact | Answers |
|---|---|
manifest.json | What does this project look like, structurally? |
run_results.json | What actually happened during the last run? |
catalog.json | What does the warehouse actually contain right now? |
sources.json | Are sources fresh enough to trust? |
dbtโs JSON artifacts are what make the projectโs internals programmatically accessible โ the foundation for orchestration integration, custom monitoring, and any tooling that needs to understand a dbt project without re-parsing its SQL from scratch.