Snowflake Warehouse Sizing: How to Pick the Right Size Without Guessing
Last updated: February 2025
Quick answer: Start with X-Small (1 credit/hour) for ad-hoc queries and Small for ETL. Check the query profile for spilling - if queries spill to remote storage, size up. Set auto-suspend to 60 seconds, not the default 600. Use separate warehouses per workload type, and set up resource monitors before your bill surprises you.
How Warehouse Sizes Work
Snowflake warehouse sizes follow a simple doubling pattern. Each step up doubles the number of compute nodes and the per-hour credit cost:
| Size | Credits/Hour | Servers (Nodes) | Typical Use |
|---|---|---|---|
| X-Small (XS) | 1 | 1 | Ad-hoc queries, development, testing |
| Small (S) | 2 | 2 | Light ETL, small BI dashboards |
| Medium (M) | 4 | 4 | Production ETL, moderate analytics |
| Large (L) | 8 | 8 | Heavy transformations, complex joins |
| X-Large (XL) | 16 | 16 | Large-scale data processing |
| 2X-Large | 32 | 32 | Very large datasets, data science workloads |
| 3X-Large | 64 | 64 | Enterprise batch processing |
| 4X-Large | 128 | 128 | Maximum single-query parallelism |
The dollar cost per credit varies by edition. On-demand Standard Edition runs roughly $2/credit. Enterprise is about $3/credit. Business Critical is around $4/credit. Check your contract for exact pricing.
The Auto-Suspend Trap
The default auto-suspend is 600 seconds (10 minutes). That means your warehouse stays running - and burning credits - for 10 minutes after the last query finishes. If your analysts run a query every 15 minutes, the warehouse barely ever suspends.
Set it to 60 seconds for interactive workloads. Snowflake bills per-second with a 60-second minimum, so there's no penalty for resuming frequently. The resume typically takes 1-2 seconds for cached warehouses.
-- Fix the default auto-suspend ALTER WAREHOUSE bi_wh SET AUTO_SUSPEND = 60 AUTO_RESUME = TRUE;
AUTO_RESUME = TRUE is on by default, but verify it. If it's off, queries queue until someone manually resumes the warehouse.
When to Size Up vs Scale Out
This is the core decision. Snowflake gives you two levers: make the warehouse bigger (size up) or add more clusters (scale out with multi-cluster warehouses).
Size Up When...
- Individual queries are slow (running 5+ minutes when you expect under 1 minute).
- The query profile shows spilling to local or remote storage.
- You're running complex joins, large aggregations, or heavy window functions.
- A single query needs more memory or CPU than the current size provides.
Scale Out (Multi-Cluster) When...
- Individual queries are fast, but too many run at the same time and they queue.
- You see queuing in the query history during peak hours (8-10 AM, end of quarter).
- Dashboard refresh spikes cause contention for 20+ concurrent users.
ALTER WAREHOUSE bi_wh SET MIN_CLUSTER_COUNT = 1 MAX_CLUSTER_COUNT = 3 SCALING_POLICY = 'STANDARD'; -- STANDARD: starts new cluster when queries queue -- ECONOMY: waits longer before scaling (saves credits, adds latency)
Identifying Spilling: The Key Signal
Spilling is the single most reliable indicator that your warehouse is undersized for a specific query. When a query's intermediate results exceed available memory, Snowflake "spills" data to disk:
- Local spill (SSD): Slower than memory, but tolerable. A few GB of local spilling on large queries is normal.
- Remote spill (S3/ADLS/GCS): Significantly slower. If you see remote spilling, your warehouse is too small for that query. Size up.
Check spilling for recent queries:
SELECT query_id, query_text, warehouse_size,
bytes_spilled_to_local_storage,
bytes_spilled_to_remote_storage,
total_elapsed_time / 1000 AS elapsed_sec
FROM snowflake.account_usage.query_history
WHERE start_time > DATEADD('day', -7, CURRENT_TIMESTAMP())
AND bytes_spilled_to_remote_storage > 0
ORDER BY bytes_spilled_to_remote_storage DESC
LIMIT 20;
Dedicated Warehouses Per Workload
Don't share a single warehouse between ETL, BI, and ad-hoc queries. Here's why: your 3 AM ETL job starts a Large warehouse and takes 45 minutes. At 8 AM, an analyst runs a dashboard refresh on the same warehouse. The analyst's query either queues behind ETL or competes for resources with it.
A better setup for most teams:
| Warehouse | Size | Auto-Suspend | Purpose |
|---|---|---|---|
ETL_WH | Medium | 60s | Scheduled pipeline runs (dbt, tasks, stored procedures) |
BI_WH | Small, multi-cluster (1-3) | 120s | Dashboard queries, Tableau/Power BI refresh |
ADHOC_WH | X-Small | 60s | Analyst exploration, ad-hoc SQL |
ML_WH | Large | 60s | Data science notebooks, model training queries |
Analyzing Actual Usage with WAREHOUSE_METERING_HISTORY
SELECT warehouse_name,
DATE_TRUNC('day', start_time) AS day,
SUM(credits_used) AS total_credits,
SUM(credits_used_compute) AS compute_credits,
SUM(credits_used_cloud_services) AS cloud_credits
FROM snowflake.account_usage.warehouse_metering_history
WHERE start_time > DATEADD('month', -1, CURRENT_TIMESTAMP())
GROUP BY warehouse_name, day
ORDER BY day DESC, total_credits DESC;
Run this monthly. If a warehouse consistently uses less than 1 credit/day, consider downsizing. If it's burning 50+ credits/day, check whether the queries could be optimized before resizing.
Resource Monitors: Your Safety Net
Resource monitors cap credit consumption with actions at defined thresholds. Set them up before you need them, not after a $15,000 surprise.
-- Create a resource monitor with email alerts and auto-suspend
CREATE RESOURCE MONITOR etl_monitor
WITH CREDIT_QUOTA = 500
FREQUENCY = MONTHLY
START_TIMESTAMP = IMMEDIATELY
TRIGGERS
ON 75 PERCENT DO NOTIFY
ON 90 PERCENT DO NOTIFY
ON 100 PERCENT DO SUSPEND;
-- Assign to a warehouse
ALTER WAREHOUSE etl_wh SET RESOURCE_MONITOR = etl_monitor;
A Sizing Decision Tree
Follow this path for each workload type:
- Start at X-Small. Run your representative queries. If most complete in under 10 seconds, stay here.
- Check the query profile. Look at the Query Profile tab in Snowflake's UI. If you see no spilling and no queuing, you're sized correctly.
- If queries are slow (30+ seconds) and spill to local storage: Try Small. Re-run the same queries.
- If queries spill to remote storage at Small: Move to Medium. Remote spilling is the definitive "too small" signal.
- If individual queries are fast but users experience queuing: Don't size up. Enable multi-cluster scaling instead.
- If a query doesn't speed up when you size up: The query isn't parallelizable. Optimize the SQL instead (better filters, fewer joins, clustering keys).
The critical gotcha: doubling the warehouse size doesn't halve query time. It depends entirely on how parallelizable the query is. A full table scan on a partitioned table scales nearly linearly. A single-row lookup or a recursive CTE won't speed up at all, regardless of warehouse size.
Key Takeaways
- Warehouse sizes double in cost at each tier: XS=1, S=2, M=4, L=8 credits/hour.
- Set auto-suspend to 60 seconds. The 10-minute default wastes credits silently.
- Size up for slow individual queries (especially those spilling to remote storage). Scale out with multi-cluster for concurrency problems.
- Use separate warehouses per workload: ETL, BI, ad-hoc, and ML should not compete for the same resources.
- Query WAREHOUSE_METERING_HISTORY monthly to identify underused or overworked warehouses.
- Set up resource monitors immediately. A 500-credit monthly cap with email alerts at 75% prevents billing surprises.
Frequently Asked Questions
Q: How much does each Snowflake warehouse size cost?
Warehouse sizes double in cost at each tier: X-Small = 1 credit/hour, Small = 2, Medium = 4, Large = 8, X-Large = 16, 2X-Large = 32, and so on. The dollar cost per credit depends on your Snowflake edition and contract (typically $2-4 per credit on-demand).
Q: What should I set auto-suspend to in Snowflake?
For interactive workloads, set auto-suspend to 60-120 seconds (1-2 minutes). The default 600 seconds (10 minutes) wastes credits since warehouses are billed per-second with a 60-second minimum. For ETL warehouses that run scheduled jobs, 60 seconds is sufficient.
Q: What does query spilling mean in Snowflake?
Spilling occurs when a query's intermediate results exceed the warehouse's available memory and must be written to local SSD (local spill) or remote storage (remote spill). Remote spilling is significantly slower. If you see remote spilling, your warehouse is undersized for that query.
Q: Does doubling warehouse size halve query time?
Not necessarily. Doubling the warehouse provides twice the compute resources, but the speedup depends on how parallelizable the query is. Highly parallel scans may see near-2x improvement. Sequential operations like single-row lookups or non-parallelizable sorts won't benefit much.
