A dashboard makes an implicit promise: the numbers on it are correct, current, and derived from the data the viewer thinks they are derived from. When that promise is not backed by any explicit validation, the promise is held by the author's confidence rather than by evidence, and confidence is not reliable protection against a pipeline that silently failed, a data source that changed its schema, or a metric definition that drifted from the business definition it was supposed to encode.
A data contract for a dashboard is the explicit version of that implicit promise: a set of documented, tested conditions that must be true about the data before the dashboard is considered valid. When the conditions are met, the dashboard is published. When they are not, the dashboard shows an error state or is pulled from publication until the issue is resolved. The contract is what makes "the dashboard is right" a claim with evidence rather than a belief.
Freshness: is the data current?
Freshness is the simplest contract condition and the one most often missing. A daily dashboard that shows yesterday's data is correct. The same dashboard showing data that is four days old because an ingestion job silently failed is wrong in a way the viewer cannot detect from the chart itself: the lines still go up or down, the numbers still look plausible, and the only signal that something is broken is the date, if the dashboard even shows one.
-- Freshness check: fail if latest data is more than 25 hours old
SELECT
MAX(loaded_at) AS latest_load,
CURRENT_TIMESTAMP AS now,
DATEDIFF('hour', MAX(loaded_at), CURRENT_TIMESTAMP) AS hours_since_load,
CASE
WHEN DATEDIFF('hour', MAX(loaded_at), CURRENT_TIMESTAMP) > 25
THEN 'STALE'
ELSE 'FRESH'
END AS freshness_status
FROM fct_orders;
The freshness threshold is a business decision: a real-time operational dashboard has a tolerance of minutes; a monthly executive report has a tolerance of days. The threshold must be documented and monitored. A dashboard that has no freshness check is a dashboard where the first indicator that the data is stale is a stakeholder noticing a number that looks wrong, which is the most expensive possible discovery mechanism.
In dbt, freshness checks are a first-class feature of source definitions:
# sources.yml
sources:
- name: ecommerce
tables:
- name: orders
freshness:
warn_after: {count: 12, period: hour}
error_after: {count: 25, period: hour}
loaded_at_field: loaded_at
A dbt source freshness run checks every source with a defined freshness expectation and fails the pipeline if any source exceeds the error threshold. The dashboard should not update if this check fails.
Completeness: is the data all there?
A dataset can be fresh and incomplete: the latest load ran on schedule and landed fewer rows than it should have. A completeness check validates that the volume of data in the current load is consistent with historical patterns.
-- Completeness check: today's order count vs. 4-week rolling average
WITH daily_counts AS (
SELECT
DATE(created_at) AS order_date,
COUNT(*) AS order_count
FROM fct_orders
WHERE created_at >= CURRENT_DATE - 35
GROUP BY 1
),
rolling_avg AS (
SELECT
order_date,
order_count,
AVG(order_count) OVER (
ORDER BY order_date
ROWS BETWEEN 28 PRECEDING AND 1 PRECEDING
) AS avg_last_28d
FROM daily_counts
)
SELECT
order_date,
order_count,
ROUND(avg_last_28d) AS rolling_avg,
ROUND(order_count / avg_last_28d, 2) AS ratio,
CASE
WHEN order_count / avg_last_28d < 0.70 THEN 'VOLUME_DROP'
WHEN order_count / avg_last_28d > 1.50 THEN 'VOLUME_SPIKE'
ELSE 'OK'
END AS completeness_status
FROM rolling_avg
WHERE order_date = CURRENT_DATE - 1;
A volume drop below 70% of the rolling average is a signal worth investigating: a source system issue, a pipeline failure that only landed part of the data, or a genuine business event. A volume spike above 150% deserves the same attention: it may be a reprocessing of historical data that duplicated rows, or a genuine volume event that happened to coincide with a load.
Consistency: do the numbers agree with each other?
A dashboard that shows revenue in two places should show the same revenue in both places. This sounds obvious and is violated constantly: a KPI tile at the top of the dashboard aggregates from one model, a chart in the body aggregates from another, and the two models apply slightly different filters. The viewer sees two different revenue figures on the same page and concludes either that the data is wrong or that they are misreading something. Both outcomes damage trust.
-- Consistency check: revenue matches across two aggregation paths
WITH path_a AS (
SELECT SUM(revenue_usd) AS revenue
FROM fct_orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31'
AND status = 'completed'
),
path_b AS (
SELECT SUM(order_amount_usd) AS revenue
FROM fct_monthly_revenue
WHERE month = '2024-01-01'
)
SELECT
path_a.revenue AS revenue_from_orders,
path_b.revenue AS revenue_from_monthly,
ABS(path_a.revenue - path_b.revenue) AS absolute_diff,
CASE
WHEN ABS(path_a.revenue - path_b.revenue) / path_a.revenue > 0.001
THEN 'INCONSISTENT'
ELSE 'CONSISTENT'
END AS status
FROM path_a, path_b;
The 0.1% tolerance in the consistency check is a judgment call: for financial metrics, it should be zero or very close to it. For operational metrics derived from sampling or approximation, a small tolerance may be appropriate. The tolerance and its rationale belong in the contract documentation, not left implicit.
The contract documentation
The contract for a dashboard is a document attached to it, visible to every consumer, that states: what data sources feed it and when they were last validated, the freshness threshold and how it is monitored, the completeness checks in place, the consistency checks across metrics, the metric definitions (not links to a definition elsewhere, the definitions themselves), and the escalation path when a check fails.
A consumer who reads the contract knows exactly what "this dashboard is right" means and exactly what the conditions are under which the data might be stale or incomplete. That consumer can make better decisions with the dashboard, ask better questions about anomalies they see, and escalate correctly when something looks wrong. A consumer without the contract is trusting in the absence of any basis for trust, which is a different and weaker thing.
The dashboard that earns its place in a business is the one that people trust enough to act on. Trust is not built by making the charts look good. It is built by showing the checks that run every time and the conditions that would prevent the dashboard from publishing if they failed. That is the contract.