Snowflake bills warehouses by the credit-second, not by the query — so there is
no native “cost per query,” and no native “cost per team.” You reconstruct both
by joining QUERY_HISTORY to your metering data and apportioning credits across
the queries that ran. The genuinely hard part is the team dimension: knowing
which user, app, or dbt model owns each query. Query tags are supposed to answer
that, and they fail the moment one team forgets to set them.
This post is about getting accurate per-team Snowflake attribution without depending on perfect query-tag discipline — and turning it into showback, chargeback, and evidence finance can actually audit. Attribution is the lever that makes every other saving accountable: if you can’t say whose cost moved, you can’t prove you saved anything.
01 / WHY IT’S HARDWhy is Snowflake cost attribution hard?
Snowflake’s billing model is the root of the difficulty. A virtual warehouse consumes credits while it is running, regardless of how many queries — or whose queries — share it. Two facts follow from that:
- There is no per-query price. A query that ran for 8 seconds on a warehouse that was already awake for someone else’s dashboard is nearly free at the margin; the same query that cold-started a warehouse is expensive. Cost is a property of warehouse time, not of the query in isolation.
- There is no per-team dimension.
WAREHOUSE_METERING_HISTORYknows credits per warehouse per hour. It does not know that the marketing team’s BI tool and the finance team’s dbt job both hammered the sameANALYTICS_WH.
So per-team cost is always an apportionment: take each warehouse’s credits, divide them across the queries that ran on it weighted by execution time, then roll those queries up by whoever owns them. The first two steps are arithmetic. The third — ownership — is where attribution lives or dies.
02 / QUERY TAGSDo you need query tags for attribution?
Snowflake’s official answer to ownership is the QUERY_TAG session parameter:
each session sets a tag, the tag lands in QUERY_HISTORY, and you group by it.
In principle, clean. In practice, query tags are a discipline problem, and
discipline does not survive a real organisation:
- A new BI tool connects and nobody configured it to set a tag.
- A dbt project sets tags; an analyst’s ad-hoc notebook does not.
- Two teams share a service account and both inherit the same tag.
- Someone refactors a connection profile and silently drops the tag.
Every gap shows up as an “untagged” bucket that quietly grows until it’s the biggest line in your report — and untagged spend is exactly the spend nobody will accept on their chargeback. You can mandate tags, write linters, and chase teams, but you are now running a governance programme to answer a question the infrastructure should answer for you.
Query tags work perfectly right up until the one team that forgot becomes the biggest line on the bill.
— the discipline tax
03 / WIRE-LEVEL ATTRIBUTIONHow chukei attributes cost without perfect query tags
chukei is a transparent wire-protocol proxy that sits in the Snowflake query path inside your own VPC. Every query crosses the wire through it, which means attribution happens at the one point where all traffic is visible — before it reaches Snowflake, regardless of which tool sent it. Instead of trusting that everyone set a tag, chukei reads ownership from the signals that are already present in real traffic:
- SQL comment hints. Leading
-- chukei: team=...style comments, or existing structured comments your tools already emit, are parsed at the wire. - dbt run metadata. dbt stamps models, runs, and invocation IDs into query comments; chukei reads them to attribute spend down to the individual model.
APPLICATION_NAMEand driver identity. The JDBC / Python connector advertises its application name and session attributes; chukei uses them to separate Looker from Tableau from a dbt job from an analyst’s notebook.
Because chukei sees the wire, attribution does not require everyone to opt in. If a tag is present, it’s used; if it isn’t, the application name and dbt metadata still pin the query to an owner. The “untagged” bucket shrinks to the genuinely anonymous, instead of swallowing every team that forgot.
Deterministic, no LLM, fail open. Attribution is parsing, not guessing — there is no model inference on the hot path, and the same query always maps to the same owner. Overhead is ~2 ms p99. If chukei can’t classify a query, it still passes it through byte-for-byte to Snowflake; attribution never blocks a query, it only annotates it.
Here is the baseline ACCOUNT_USAGE query most teams start with — apportioning
credits to individual queries by runtime to estimate cost per query:
-- Estimate Snowflake cost per query: apportion warehouse credits by runtime.
with metering as (
select
warehouse_id,
date_trunc('hour', start_time) as hr,
sum(credits_used_compute) as wh_credits
from snowflake.account_usage.warehouse_metering_history
where start_time >= dateadd('day', -30, current_timestamp())
group by 1, 2
),
runtime as (
select
warehouse_id,
date_trunc('hour', start_time) as hr,
sum(execution_time) as wh_exec_ms
from snowflake.account_usage.query_history
where start_time >= dateadd('day', -30, current_timestamp())
and warehouse_id is not null
group by 1, 2
)
select
q.query_id,
q.query_tag, -- often null in real life
q.warehouse_name,
q.execution_time / 1000.0 as seconds,
-- query's share of its warehouse-hour credits, times your $/credit:
round(m.wh_credits * (q.execution_time / nullif(r.wh_exec_ms, 0)) * 3.00, 4)
as est_cost_usd
from snowflake.account_usage.query_history q
join metering m
on q.warehouse_id = m.warehouse_id
and date_trunc('hour', q.start_time) = m.hr
join runtime r
on q.warehouse_id = r.warehouse_id
and date_trunc('hour', q.start_time) = r.hr
where q.start_time >= dateadd('day', -30, current_timestamp())
order by est_cost_usd desc
limit 100;
That query gives you cost per query — but it can only roll up by team as far
as query_tag is populated. This is exactly the gap chukei’s wire-level owner
fills. With ownership resolved at the wire, the same spend rolls up cleanly into
a cost by team report:
| Team / owner | Source signal | 30-day credits | Est. cost | Share |
|---|---|---|---|---|
| Analytics (dbt) | dbt run metadata | 1,840 | $5,520 | 38% |
| BI — Looker | APPLICATION_NAME | 1,290 | $3,870 | 27% |
| Finance reporting | SQL hint | 760 | $2,280 | 16% |
| Data science | APPLICATION_NAME | 540 | $1,620 | 11% |
| Ad-hoc / notebooks | driver identity | 380 | $1,140 | 8% |
Note what’s not there: a giant “untagged” row. Every credit is pinned to an owner because the owner came from signals already in the traffic, not from a tag someone had to remember to set.
04 / SHOWBACK TO CHARGEBACKFrom showback to chargeback
Accurate per-team numbers unlock the FinOps maturity ladder:
- Showback — publish each team’s Snowflake spend for visibility. No money moves; the goal is behaviour change. Teams that can see their dashboard refresh cost tend to fix it without being told to.
- Chargeback — bill that spend back to the team’s budget. Same attribution, plus the accounting step. Chargeback only works once the numbers are trusted, which is why teams start with showback and graduate.
The thing that stalls most chargeback efforts is disputes: a team refuses a bill they can’t verify, the untagged bucket gets argued over, and the programme dies. Wire-level attribution removes the easy objection (“that’s not ours / that’s untagged”), because every line traces to a concrete source signal.
05 / SIGNED EVIDENCECan finance audit Snowflake chargeback?
For chargeback to survive contact with finance, the numbers have to be auditable — not “trust the dashboard.” chukei writes attribution and savings as Ed25519-signed JSON evidence with a conservative, reproducible methodology. Finance can verify the signature, re-run the apportionment, and confirm exactly which credits were assigned to which team. The same signed-evidence approach underpins chukei’s savings reports, so a saving and its owner are provable in the same artifact.
This is the honest differentiator. Commercial hosted optimizers (Keebo, Espresso AI, SELECT.dev, and others) do strong cost analysis, but they’re vendor-hosted, and you take their attribution on faith. OSS dashboards (dbt-snowflake-monitoring, homegrown SQL) are transparent but sit outside the query path, so they inherit the same tag-discipline gap as everyone else. chukei is the option that attributes in the path and signs the result — and it’s Apache-2.0 and self-hosted, so your SQL, credentials, and data plane never leave your VPC.
Key takeaways
- Snowflake has no native per-query or per-team cost — both are apportionments of warehouse credits, and the owner dimension is the hard part.
- Query tags fail on discipline: one untagged tool becomes the biggest line on the bill. You don’t need them with wire-level attribution.
- chukei reads ownership from SQL hints, dbt metadata, and
APPLICATION_NAMEat the wire — deterministically, no LLM, ~2 ms p99, fail-open. - Showback → chargeback works only when numbers are trusted; Ed25519-signed evidence lets finance audit every credit attributed.
Attribution is the lever that makes every other saving accountable — pair it with cost monitoring to explain the bill, cost benchmarks to know if it’s high, and the cornerstone Snowflake cost optimization guide for the full playbook. The attribution lever ships in the Apache-2.0 release; the docs walk through wiring it into your own account.
Frequently asked questions
- How do I see Snowflake cost per team?
- Join SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY to WAREHOUSE_METERING_HISTORY to convert query runtime into credits, then group by a team identifier — a query tag, role, or session attribute. The hard part is the team identifier: tags require discipline, so chukei instead reads the team from SQL hints, dbt metadata, and APPLICATION_NAME at the wire, so attribution holds even when tags are missing.
- How do I calculate Snowflake cost per query?
- Snowflake bills warehouses by credit-second, not per query, so there is no exact per-query price. You approximate it by apportioning each warehouse's credits across the queries that ran on it, weighted by execution time. Multiply credits by your per-credit rate to get a dollar estimate per query.
- What is the difference between showback and chargeback?
- Showback reports each team's Snowflake spend for visibility without moving any money. Chargeback bills that spend back to the team's budget. Both need the same accurate per-team attribution; chargeback just adds the accounting step, so most teams start with showback and graduate to chargeback once the numbers are trusted.
- Do I need query tags for Snowflake cost attribution?
- No. Query tags work only when every tool and team sets them perfectly, which rarely holds. chukei attributes spend at the wire from SQL comment hints, dbt run metadata, and the driver's APPLICATION_NAME, so you get per-team cost ownership without depending on tag discipline.
- Can finance audit Snowflake chargeback numbers?
- With chukei, yes. Attribution and savings evidence are written as Ed25519-signed JSON with a conservative, reproducible methodology, so finance and audit can verify exactly which credits were attributed to which team without trusting a dashboard.
Works on the cost-modelling and replay engine at OSO. Previously spent too long staring at Snowflake bills that nobody could explain.