+1 (415) 997-4269

Cutting Your Snowflake Bill in 2026: Gen2 Warehouses, Adaptive Compute, and the Classics

Snowflake bills are rarely high because of one expensive thing. They are high because of a dozen cheap things nobody owns: a warehouse that never suspends, a dashboard that refreshes every minute, a retention setting copied from a template, a Medium warehouse running X-Small work. The good news is that all of it is visible in ACCOUNT_USAGE, and most of it is fixable with ALTER statements.

This guide covers the 2026 additions — Gen2 warehouses and Adaptive Compute — and the classics that still deliver most of the savings.

Gen2 warehouses: when to switch

Generation 2 standard warehouses run on newer hardware with engine improvements aimed at analytics and DML-heavy workloads — large scans, joins, MERGE, DELETE, and UPDATE. They are priced at a higher credit rate per hour than Gen1, which means the decision is empirical: a workload that finishes enough faster on Gen2 costs less in total; one that does not costs more.

Switching is one statement:

ALTER WAREHOUSE etl_wh SET RESOURCE_CONSTRAINT = STANDARD_GEN_2;
-- and back, if the benchmark says so:
ALTER WAREHOUSE etl_wh SET RESOURCE_CONSTRAINT = STANDARD_GEN_1;

Benchmark honestly: run the same production workload (not a synthetic query) for a full day on each generation, then compare credits from WAREHOUSE_METERING_HISTORY and wall-clock from QUERY_HISTORY. Transformation and ELT warehouses are the usual winners; tiny lookup warehouses that already finish in seconds often are not. Check the documentation for Gen2 region availability and size limits before planning around it.

Adaptive Compute

Adaptive Compute is Snowflake's automatically managed compute: you create an adaptive warehouse, and Snowflake picks the cluster size and count per query from a shared pool, instead of you choosing WAREHOUSE_SIZE and MAX_CLUSTER_COUNT.

CREATE WAREHOUSE analytics_adaptive_wh
  WAREHOUSE_TYPE = 'ADAPTIVE'
  AUTO_SUSPEND = 60;

It is the right answer for mixed, spiky BI workloads where right-sizing by hand was always a compromise. It is a weaker fit for a steady ETL batch that you have already tuned to a size. Check its availability and the current billing model in your region before adopting; as a newer feature its terms have changed since preview.

The classics

1. Auto-suspend and auto-resume hygiene

The single most common leak. Every warehouse should have AUTO_RESUME = TRUE and an AUTO_SUSPEND that matches its use:

-- Find warehouses with no auto-suspend or a long one
SHOW WAREHOUSES;
SELECT "name", "size", "auto_suspend", "auto_resume"
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "auto_suspend" IS NULL OR "auto_suspend" > 300;

ALTER WAREHOUSE reporting_wh SET AUTO_SUSPEND = 60;

Sixty seconds is a sensible default for interactive warehouses; the billing minimum is 60 seconds per resume anyway. Go longer only where cache reuse measurably matters.

2. Right-sizing with WAREHOUSE_METERING_HISTORY

Credits per warehouse per day, with load:

SELECT m.warehouse_name,
       DATE_TRUNC('day', m.start_time)            AS day,
       SUM(m.credits_used)                        AS credits,
       AVG(l.avg_running)                         AS avg_running_queries,
       AVG(l.avg_queued_load)                     AS avg_queued
FROM snowflake.account_usage.warehouse_metering_history m
LEFT JOIN snowflake.account_usage.warehouse_load_history l
  ON l.warehouse_name = m.warehouse_name AND l.start_time = m.start_time
WHERE m.start_time >= DATEADD(day, -30, CURRENT_TIMESTAMP())
GROUP BY 1, 2
ORDER BY credits DESC;

Read it with two questions: a warehouse with high credits and avg_running_queries well under 1 is oversized or never suspends; one with persistent avg_queued is undersized or needs multi-cluster. Then look at the queries themselves:

SELECT warehouse_name, warehouse_size,
       COUNT(*)                                         AS queries,
       AVG(total_elapsed_time)/1000                     AS avg_secs,
       SUM(bytes_spilled_to_local_storage)/1e9          AS gb_spilled_local,
       SUM(bytes_spilled_to_remote_storage)/1e9         AS gb_spilled_remote
FROM snowflake.account_usage.query_history
WHERE start_time >= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND warehouse_name IS NOT NULL
GROUP BY 1, 2
ORDER BY gb_spilled_remote DESC;

Remote spill means the warehouse is too small for those queries; no spill and sub-second queries on a Large means it is too big. Sizes are a doubling scale, so one step down halves the hourly rate. QUERY_ATTRIBUTION_HISTORY gives per-query credit attribution if you want to rank individual offenders.

3. Query Acceleration Service

When a warehouse is sized for its handful of outlier queries, shrink it and let QAS handle the outliers:

-- Which queries would benefit, and by how much?
SELECT query_id, eligible_query_acceleration_time, upper_limit_scale_factor
FROM snowflake.account_usage.query_acceleration_eligible
WHERE start_time >= DATEADD(day, -7, CURRENT_TIMESTAMP())
ORDER BY eligible_query_acceleration_time DESC
LIMIT 20;

ALTER WAREHOUSE reporting_wh SET
  ENABLE_QUERY_ACCELERATION = TRUE
  QUERY_ACCELERATION_MAX_SCALE_FACTOR = 8;

QAS bills serverless credits only when it actually accelerates something, which is usually far cheaper than keeping the whole warehouse two sizes up.

4. Budgets and resource monitors

Resource monitors are the hard stop; budgets are the early warning.

CREATE OR REPLACE RESOURCE MONITOR marketing_rm WITH
  CREDIT_QUOTA = 500
  FREQUENCY = MONTHLY
  START_TIMESTAMP = IMMEDIATELY
  TRIGGERS ON 80 PERCENT DO NOTIFY
           ON 100 PERCENT DO SUSPEND
           ON 110 PERCENT DO SUSPEND_IMMEDIATE;

ALTER WAREHOUSE marketing_wh SET RESOURCE_MONITOR = marketing_rm;

Budgets (SNOWFLAKE.CORE.BUDGET) cover what resource monitors cannot — serverless features such as Snowpipe, Dynamic Tables, Cortex, and search services — and can be scoped to a group of objects or the whole account, with notifications when the projected spend will exceed the limit. Put an account-level budget in place even if it only sends email; it is the number finance asks about.

5. Storage: Time Travel and Fail-safe

Storage is cheaper than compute but it compounds quietly. Three checks:

-- Tables where Time Travel / Fail-safe storage dwarfs the active bytes
SELECT table_catalog, table_schema, table_name,
       active_bytes/1e9       AS active_gb,
       time_travel_bytes/1e9  AS tt_gb,
       failsafe_bytes/1e9     AS fs_gb
FROM snowflake.account_usage.table_storage_metrics
WHERE (time_travel_bytes + failsafe_bytes) > active_bytes
ORDER BY tt_gb + fs_gb DESC
LIMIT 50;
  • Set DATA_RETENTION_TIME_IN_DAYS deliberately — 1 for staging and raw landing tables, more only for tables where a restore would matter.
  • Use TRANSIENT tables for anything rebuildable (staging, intermediate models); they skip Fail-safe entirely.
  • High-churn tables (truncate-and-load, frequent DELETE) generate Time Travel storage equal to the table size on every cycle. Those are the ones to make transient.
  • Drop forgotten clones and zero-copy experiments; a clone is free until the source changes, then it is not.

A 30-day plan

  1. Week 1: audit with the queries above; fix auto-suspend everywhere; set an account budget.
  2. Week 2: downsize the two or three warehouses with the most idle credits; enable QAS where the eligibility view shows a win.
  3. Week 3: benchmark Gen2 on the ETL warehouse; make staging tables transient and set retention.
  4. Week 4: attach resource monitors to every team warehouse; build a chargeback view so each team can see its own line.

Then measure the next cycle against the last one — the only metric that counts.

Want an independent audit? See our Snowflake cost optimization service or contact us.