Warehouse Sizes, Auto-Suspend, and the Credit Meter

In Snowflake you don't rent a server, you buy compute-seconds — which means cost is something you design, and a warehouse left running is money on fire.

The bill for a traditional database is a server you rented, and it costs the same whether you hammered it all month or let it idle. Snowflake tears that model up. Here you don’t pay for a machine sitting there — you pay for compute-seconds, the actual time a warehouse spends running your queries. That one change moves cost out of the finance department’s spreadsheet and into your SQL. How much you spend is now a thing you design, query by query and warehouse by warehouse. And the first design mistake everyone makes is leaving a warehouse running while they stare at the results, which is the cloud equivalent of leaving the car engine on in the driveway.

A warehouse, to be concrete, is just a named cluster of compute that runs your queries. It has no data of its own — the data lives in cloud storage, and any warehouse can read any table your role can see. That separation is the whole reason cost is malleable: you can run a huge warehouse for the two minutes a rebuild needs, drop it, and spin up a tiny one for dashboards, all pointed at the same tables, none of them holding anything hostage. This chapter is about the two things a warehouse controls — how fast it burns money and how long — and how those turn into a number on an invoice.

The credit meter

Snowflake bills compute in credits. A warehouse consumes credits at a rate set by its size, and only while it’s actually running — the second it suspends, the meter stops. What a credit costs in dollars depends on your edition, cloud, and region, so don’t hard-code a figure in your head. A Standard-edition credit is cheaper than an Enterprise one, which is cheaper than Business Critical; think “a few dollars” and leave it fuzzy until you look up your own rate. We’ll turn credits into dollars near the end, but the mechanics come first.

The billing granularity is the part worth internalizing: per-second, with a 60-second minimum each time a warehouse resumes. Wake a warehouse, run a two-second query, and you’re charged for a full minute. Wake it, run for three minutes, and you pay for three minutes — after the first minute, the meter is truly per-second, no rounding up to the next hour like the old cloud-VM world. So a hundred tiny queries that each cold-start a fresh warehouse can cost more than one long one — the 60-second floor punishes stop-start churn. The lesson isn’t to avoid stopping; it’s to avoid thrashing between stopped and started, which the auto-suspend timing below controls.

Compute is the meter you’ll watch most, but it isn’t the only one. It helps to hold the whole bill in your head at intro level, because a “why is this so expensive” question usually turns out to be one of the quieter meters:

  • Compute credits — your warehouses, billed per-second as above. This is the big, visible number and the one you design.
  • Cloud-services credits — the always-on brain of Snowflake (query planning, the optimizer, metadata, security, result caching) runs on a shared layer that also consumes credits. But there’s a break most people don’t know about: cloud-services usage is only charged for the portion that exceeds 10% of your daily compute credits. Burn 100 compute credits in a day and your first 10 credits of cloud-services work are free. For normal query workloads this means cloud services costs you effectively nothing; it only shows up on the bill when you do something metadata-heavy and compute-light, like hammering INFORMATION_SCHEMA or running thousands of tiny DDL statements against a barely-used warehouse.
  • Storage — billed in dollars per terabyte per month, on the compressed size of your data (Snowflake stores everything columnar and compressed, so a raw 1 TB CSV lands far smaller). Two rates exist: on-demand, where you pay as you go, and capacity, where you pre-commit to a volume up front for a lower per-TB rate. Storage is usually a small fraction of a compute-heavy account, but Time Travel and Fail-safe retention (the next chapter) quietly add to it.
  • Serverless features — some Snowflake capabilities run on compute that Snowflake manages for you rather than on your warehouses: Snowpipe, automatic clustering, materialized-view maintenance, search optimization, serverless tasks, and the Query Acceleration Service below. These bill in credits at their own per-feature rates and show up on separate lines. You don’t size them; you enable them and they scale themselves.

Storage, cloud services beyond the 10% line, serverless rates, and the edition-by-edition pricing are the province of the cost-governance chapter — Cost, Credits, and Resource Monitors. Here we stay on the warehouse.

The size ladder

A warehouse comes in T-shirt sizes, and each step up roughly doubles both the compute and the credit rate:

XS     1 credit/hour
S      2
M      4
L      8
XL     16
2XL    32
3XL    64
4XL    128
5XL    256
6XL    512

The doubling is the whole story, and it runs all the way from a 1-credit XS to a 512-credit 6XL. Under the hood each size step doubles the number of servers in the cluster, which is why the rate doubles — you’re renting twice the machines for the hour. Here’s the part that isn’t obvious: a bigger warehouse is often not more expensive for the same work. A query that takes eight minutes on a Small might take one minute on a Large. The Large burns credits eight times faster but runs one-eighth as long — same total credits, and you got your answer seven minutes sooner. When a query parallelizes cleanly across those extra servers, sizing up buys you speed close to free.

“Close to free” is the honest phrasing, not “free,” because scaling is rarely perfectly linear. Some queries have a serial bottleneck — a final sort, a single-threaded step, spilling to disk — that a bigger warehouse can’t halve. The practical move is to measure: run the real query one size up and check whether the wall-clock time actually roughly halved. If it did, the credits are a wash and you keep the speed; if it barely moved, you sized up into a bottleneck and you’re now paying double for nothing. Query Acceleration, later in this chapter, is one answer when the bottleneck is a big scan rather than the compute width.

The trap is the other direction. Point a Large at a query that only ever touches a few thousand rows and you’re paying the 8-credit rate for work an XS would’ve cleared in the same wall-clock time. Now the doubling is pure waste. So the rule is size to the workload, not to the biggest number you’re allowed: heavy scans and big rebuilds earn a large warehouse for the minutes they run; dashboards and ad-hoc pokes belong on an XS. The SF1-versus-SF100 wait you felt in the sample-data post was exactly this signal — a query outgrowing its compute — and resizing is the answer to it.

The two switches that save the most

Right-sizing controls the rate. Two warehouse settings control the duration, and they’re where most wasted money hides.

AUTO_SUSPEND is the idle timeout — how long a warehouse waits, doing nothing, before it powers itself down. The default is 10 minutes, which for interactive work is ten minutes of paying for silence every time you get distracted. Set it low. Sixty seconds is a sane default for a warehouse a human is typing against:

USE ROLE SYSADMIN;   -- objects should be owned by the role that should own them (ch07)

CREATE WAREHOUSE analyst_wh
  WAREHOUSE_SIZE = 'XSMALL'
  AUTO_SUSPEND = 60
  AUTO_RESUME = TRUE;

-- A warehouse nobody can use is an expensive ornament. Creating it does NOT
-- grant it: the role that will run queries on it needs USAGE, explicitly.
GRANT USAGE ON WAREHOUSE analyst_wh TO ROLE analyst;

That last line is the one people forget, and the error it produces is unhelpfully vague. A warehouse is an object like any other, and USAGE is the privilege to run queries on it. Create a warehouse as SYSADMIN, hand your analyst a role that can read every table in the schema, and they will still be unable to run a single query — because they can select from the data and have nowhere to compute it. Grant the warehouse and the table; either alone is useless.

AUTO_RESUME is the other half of the same idea: with it on, a warehouse that suspended itself wakes automatically the instant a query arrives. You never manually turn it back on — the query does. Together the pair means a warehouse is running only during the seconds you’re actually asking it questions, and costs nothing across the long stretches you’re reading, thinking, or in a meeting.

There’s a tension to tune, not ignore. Suspend too aggressively and a bursty workload keeps paying the 60-second minimum on every cold start; suspend too lazily and you pay for idle. For a human at a keyboard, a short timeout wins — the churn cost is small and the idle savings are large. For a warehouse serving steady automated traffic, a longer timeout keeps it warm between jobs. Either way you don’t resize to change cost here; you ALTER the timing:

ALTER WAREHOUSE analyst_wh SET AUTO_SUSPEND = 120;

And when a query genuinely does outgrow its size, resize live — no recreate, no downtime:

ALTER WAREHOUSE analyst_wh SET WAREHOUSE_SIZE = 'LARGE';

The next query lands on the bigger cluster. Bump it back down when the heavy job is done.

The cache you throw away when you suspend

There’s a hidden cost to both switches that nobody warns you about. A running warehouse keeps a local disk cache — the raw table data it has already pulled from cloud storage sits on the warehouse’s own SSDs, so a follow-up query that touches the same columns skips the fetch and runs faster. That cache is warm compute’s quiet reward for staying up.

It is lost when the warehouse suspends, and lost again when you resize — a resize provisions fresh servers, and the new cluster starts cold. So the first query after a suspend (or after an ALTER ... SET WAREHOUSE_SIZE) re-reads from storage and runs slower than the warm repeat you got a minute earlier. This is the real tension inside AUTO_SUSPEND: a very short timeout saves idle credits but throws away the cache more often, making the next query cold. For a warehouse serving a steady dashboard that re-reads the same tables all day, a slightly longer timeout can be cheaper overall, because keeping the cache warm avoids repeated cold scans. Measure both meters, not just the idle one.

One cache does survive suspend: the result cache. If you re-run byte-for-byte the same query and the underlying data hasn’t changed, Snowflake returns the stored result from the cloud-services layer in milliseconds, using no warehouse at all — it’ll even answer while the warehouse is suspended. That’s genuinely near-free, but don’t let it fool your measurements: a result-cache hit isn’t a fast warehouse, so change a literal (or add a nonce) when you actually want to time a cold run.

Up versus out: multi-cluster warehouses

Sizing up makes a single query faster. It does nothing for a hundred people running queries at once — that’s a concurrency problem, not a horsepower one. Every warehouse can only run so many statements side by side before the rest wait in a queue; a bigger warehouse runs each of those faster but doesn’t widen the door. For concurrency, Snowflake scales out: a multi-cluster warehouse runs several clusters of the same size behind one name, spinning up extra clusters when the queue backs up and retiring them when the crowd thins. Scale up for one heavy query; scale out for many light ones arriving together. Reaching for the wrong knob is a classic misdiagnosis — a bigger warehouse won’t drain a queue, and more clusters won’t speed up a single grind.

Multi-cluster is an Enterprise-edition (and above) feature. On Standard edition a warehouse is always exactly one cluster; the settings below simply aren’t available. You configure the range with two parameters:

CREATE WAREHOUSE bi_wh
  WAREHOUSE_SIZE = 'SMALL'
  MIN_CLUSTER_COUNT = 1
  MAX_CLUSTER_COUNT = 4
  SCALING_POLICY = 'STANDARD'
  AUTO_SUSPEND = 120
  AUTO_RESUME = TRUE;

MIN_CLUSTER_COUNT and MAX_CLUSTER_COUNT set the floor and ceiling on how many same-size clusters can run. When they’re equal, you’re in maximized mode — a fixed wall of clusters, always on when the warehouse is up, for predictable heavy concurrency. When the min is lower than the max (the common case), you’re in auto-scale mode: Snowflake keeps MIN_CLUSTER_COUNT running and adds clusters up to MAX_CLUSTER_COUNT as concurrency demands, then removes them as it fades. Each running cluster bills at the warehouse’s size rate independently, so a Small warehouse running three clusters costs 3 × 2 = 6 credits/hour for as long as all three are up. The ceiling is your cost cap: MAX_CLUSTER_COUNT is literally the most compute this warehouse can ever consume at once.

The scaling policy: STANDARD vs ECONOMY

SCALING_POLICY decides how eagerly Snowflake adds and removes clusters, and it’s a direct performance-versus-cost dial.

STANDARD (the default) favors starting queries over saving credits. It spins up an additional cluster the moment a query is queued — or the moment the system judges the current clusters can’t keep up — so users wait as little as possible. To scale back down, it watches at roughly one-minute intervals and shuts a cluster off after a couple of consecutive checks show the remaining clusters could absorb the load. Fast to react, quick to relieve pressure, slightly more generous with credits.

ECONOMY favors keeping clusters busy over starting them fast. Before launching another cluster it estimates whether there’s enough queued work to keep that cluster occupied for at least about six minutes; if not, it makes the existing clusters shoulder the queue instead. It’s also slower to shut clusters down, waiting for more consecutive idle checks. The trade is deliberate: queries may sit in the queue a little longer at the edges of a spike, but you don’t pay to briefly light up a cluster for a handful of stragglers. Use ECONOMY where a short wait is acceptable and cost discipline matters (batch, internal reporting); keep STANDARD where humans are staring at a spinner.

You can change either at any time on a live warehouse:

ALTER WAREHOUSE bi_wh SET
  MAX_CLUSTER_COUNT = 6
  SCALING_POLICY = 'ECONOMY';

A note on the two axes together: size and cluster count are independent. Size is how powerful each cluster is (per-query speed); cluster count is how many of them run (concurrent capacity). A crowd of heavy queries wants both — a larger size and a higher max cluster count. Tuning them one at a time, with the query queue as your signal, beats guessing at both.

Statement timeouts and the concurrency ceiling

Within a single cluster, how many statements run at once before the rest queue is governed by MAX_CONCURRENCY_LEVEL, which defaults to 8. When more than that many queries hit a cluster together, the extras wait — and in a multi-cluster warehouse, a sustained queue is exactly what triggers another cluster to spin up. Lowering MAX_CONCURRENCY_LEVEL gives each running query a larger slice of the warehouse (useful when your queries are individually heavy and you’d rather they not fight for memory and spill to disk); raising it packs more small queries onto each cluster before queuing kicks in. It’s a subtle knob — most accounts leave it at 8 — but it’s the reason two identical warehouses can behave differently under load.

Two timeouts keep runaway work from quietly draining credits:

ALTER WAREHOUSE analyst_wh SET
  STATEMENT_TIMEOUT_IN_SECONDS = 3600
  STATEMENT_QUEUED_TIMEOUT_IN_SECONDS = 300;

STATEMENT_TIMEOUT_IN_SECONDS is the longest a single statement may run before Snowflake cancels it. The default is 172800 seconds — 48 hours — which is really a safety net, not a limit; a runaway query can burn two days of credits before it trips. On any real warehouse, set this to something sane (an hour, a few hours) so a pathological query dies instead of billing all weekend.

STATEMENT_QUEUED_TIMEOUT_IN_SECONDS is the longest a statement may wait in the queue before being cancelled, and it defaults to 0, meaning “wait forever.” Setting it to a few minutes means that when a warehouse is saturated, latecomers fail fast instead of piling up — often what you want behind a dashboard, where a stale query is worthless anyway. Both parameters can be set at the account, warehouse, session, or even user level, with the more specific scope winning.

Two specialized warehouse tricks

Query Acceleration Service attacks the case where a query’s cost is a giant scan rather than compute width. Turn it on with ENABLE_QUERY_ACCELERATION = TRUE, and Snowflake will offload the scan-and-filter-heavy parts of eligible queries onto transient serverless compute, so a warehouse that’s normally sized for its steady workload can borrow burst capacity for the occasional monster query instead of being permanently oversized for it. You cap the borrow with QUERY_ACCELERATION_MAX_SCALE_FACTOR (default 8 — up to eight times the warehouse’s own compute):

ALTER WAREHOUSE transform_wh SET
  ENABLE_QUERY_ACCELERATION = TRUE
  QUERY_ACCELERATION_MAX_SCALE_FACTOR = 8;

The offloaded work bills as a serverless feature, on its own line, separate from the warehouse’s credits — so it’s real money, not a free lunch, but you only pay it on the queries that actually qualify. It shines for unpredictable, scan-bound analytics; it does nothing for queries whose cost is joins, sorts, or aggregation.

Snowpark-optimized warehouses are a different build of warehouse for memory-hungry work — large Python/Java UDFs, ML training, and other Snowpark workloads that would blow out a normal warehouse’s per-node memory. You request one at creation with WAREHOUSE_TYPE = 'SNOWPARK-OPTIMIZED'; it provides substantially more memory per node and costs more credits per hour than a standard warehouse of the same size. Most foundational analytics never needs one — reach for it only when a job is failing on memory, not for ordinary SQL.

Putting dollars on it

Everything above is credits. Credits become dollars by multiplying by your per-credit rate, which depends on edition/cloud/region — so pick a placeholder to build intuition and swap your real rate in later. Say $3 per credit for the worked example below.

Here’s a realistic small-team day, three warehouses doing three jobs:

Warehouse     Size  Rate      Active time      Credits
analyst_wh    XS    1  cr/hr   ~3 h of queries    3.0
transform_wh  M     4  cr/hr   45 min nightly     3.0
bi_wh (×1)    S     2  cr/hr   ~2 h of dashboards 4.0
                                        Total    ~10 credits

The analyst_wh was “up” far more than three hours across the day, but with AUTO_SUSPEND = 60 it only billed for the roughly three hours of actual query activity — the rest was suspended silence at zero cost. The nightly transform ran a Medium for 45 minutes: 4 credits/hour × 0.75 hour = 3 credits. The BI warehouse served dashboards on a Small, mostly one cluster, adding up to about two active hours.

Ten compute credits at $3 is $30 for the day — call it $900/month if every day looked the same. Cloud services that day might be, say, 0.8 credits of planning and metadata work; since that’s under the 10%-of-10-credits free allowance (1 credit), it’s $0 charged. Storage is separate and, for a small account, likely a few dollars a month on compressed data. Now play the counterfactual: leave analyst_wh on the 10-minute default suspend and never think about it, and those three active hours balloon toward eight or ten billed hours of mostly-idle XS — several extra dollars a day, every day, for nothing. Scale that carelessness across a big account and multi-cluster warehouses, and “we forgot to set auto-suspend” becomes a five-figure line item. The knobs are small; the leverage is not.

To see your own real numbers instead of a made-up $3, two places tell you the truth: Admin → Cost Management in Snowsight gives you the visual breakdown, and the WAREHOUSE_METERING_HISTORY view (in ACCOUNT_USAGE and INFORMATION_SCHEMA) gives you credits per warehouse per hour in SQL. And the hard guardrail — resource monitors, which set a credit quota and can notify or even suspend a warehouse when it’s breached — is how you stop a mistake from running all month. We introduce them here only as the safety net they are; the full treatment, along with metering views and edition pricing, lives in Cost, Credits, and Resource Monitors.

Final thoughts

The instinct carried over from rented servers is to provision for the worst case and let it run, because that’s what kept you safe when the box was fixed. In Snowflake that instinct is exactly backwards. The platform hands you three dials — a rate knob (size), a duration knob (suspend timing), and a concurrency knob (clusters) — and puts the wheel in your hands. Size up for a slow query, out for a crowded one, and down to nothing the moment work stops. Cost stops being a number you receive at the end of the month and becomes a consequence of choices you make in the CREATE statement — which is either liberating or terrifying depending on whether you’ve set AUTO_SUSPEND low. Set it low.

Next: Time Travel and Zero-Copy Clones

Comments