
[Note: this post corrects a previous version that had a few placeholders instead of links]
Previously, we explored the pricing models of BigQuery and Redshift (and Serverless Redshift). In this article, we'll look at Snowflake's pricing models and optimizations that can be made to both reduce cost (which can be significant!) and improve performance.
Snowflake offers a wide range of features which gives us a lot of options when it comes to reducing cost and improving performance. However, many of these options come with pros and cons that vary from use case to use case, so we’ll also look at ways to ensure these tradeoffs are well-informed.
Since these tradeoffs can be complex, a good way to get started is with some proven best practices. We’ve compiled some below, tried and tested with our client base, to help you get started.
Understanding Snowflake’s pricing model
Snowflake’s flexible pricing model is mainly based on three components: Compute, Storage, and Cloud Services. Snowflake offers contracts with reduced pricing, or “Capacity pricing”. Some more advanced features may incur additional costs.
The prices below are as of March 1, 2025 and more details can be found on Snowflake’s Service Consumption Table (pdf). More general pricing information can be found on their Pricing Options page.
Compute
Snowflake offers a credit-based pricing model in which different sized warehouses cost different amounts of credits:
X-Small: 1 credit/hour
Small: 2 credits/hour
Medium: 4 credits/hour
Large: 8 credits/hour
… and so on up to 6XL (scales exponentially)
The cost per credit varies between about $2 and over $6 depending on the plan, region, and platform (AWS, Azure, and GCP are currently supported).
To save compute resources, warehouses auto-suspend when not in use.
Storage
Storage is charged separately from Compute and is billed by TB per month. This cost varies by plan and region but ranges between $23 and $46 per TB/month.
Data is compressed to reduce actual storage cost.
Cloud Services
Snowflake's cloud services are priced using a fair-use model. Some features incur additional cost such as SSO and query optimization. These fees are typically small and included in compute costs, as long as cloud services usage doesn't exceed 10% of compute costs.
Tiers
On-Demand
Pay-as-you-go model
Capacity
Pre-purchased credits: per-credit rates may be reduced by 30+%
Storage costs can also be reduced
Other Costs
Charges apply for transferring data to external services and between regions.
Snowflake doesn’t charge an ingress fee, but other services might have their own egress fees.
Some other features are not included in the “fair-use” model: Snowpipe, Materialized View Maintenance, Search Optimization.
Realistic pricing breakdown example
These rates are reasonable but they can add up quickly. Consider this real-world example: BigDataCo, an Ad Tech company, needs to process real-time ad impressions, clickstream data, and audience segmentation. BigDataCo’s employees regularly run complex queries on historical data to optimize ad targeting, measure campaign performance, and refine audience segmentation strategies.
Data Volume: ~300 TB stored
Users: 25 data engineers, 100 analysts, automated workloads
Compute Needs: Multiple warehouses (Small & Large), Snowpipe for streaming data ingestion
Storage
Let’s say we want to store 300TB (and this doesn’t change). At $23/TB/month, this comes out to $6,900/month.
Compute
Let’s assume ETL runs a large warehouse for 240 hours/month, analysts run 240 hours worth of medium warehouse compute, and automated workloads run small warehouses for a monthly total of 120 hours.
Adding this all up, we get (240 * 8) + (240 * 4) + (120 * 2) for a total of 3,120 credits.
Billed at $3/credit, this comes out to $9,360/month.
Cloud Services - Data transfer
Snowflake does not provide specific rates but for this example we can assume it is negligible.
Total
$6,900 + $9,360 = $16,260/month
Reducing cost and improving performance
There are plenty of ways to optimize warehouse cost and performance and this is by no means an exhaustive list. These are some ways we’ve reduced cost and improved efficiency for our customers.
Capacity Pricing
Using Capacity pricing can reduce the token costs by up to 30%. If we can accurately predict our spend for the example above, we can reduce our monthly spend to $13,452 – an overall reduction of 17%! At larger spend, Capacity pricing can save on storage costs as well.
However, accurately predicting future usage (to avoid paying for a larger commitment than needed) requires understanding historical usage, workload patterns, and expected growth.
Breaking down previous usage patterns can give more accurate results. For example, if we expect our above ETL workloads to increase by 20%, analysis workloads to increase by 10%, and automated workloads to stay constant, we can calculate that our credit usage will increase from 3,120 to 3,600 (assuming the warehouse sizes don’t change). This can give a more accurate prediction than a more holistic approach would.
After receiving reduced rates, it’s important to set up regular reviews to compare expected and actual usage and adjust warehouse sizes, schedules, or commitment levels as needed.
Optimizations

Snowflake operates on a few principles that are important to consider holistically. Unlike many other databases, Snowflake is highly optimized for analytics and uses a combination of micro-partitions and columnar storage to improve query performance and storage efficiency.
Micro-partitions are immutable storage units of about 50MB to 500MB (when uncompressed). Within each micro-partition, data is stored by column rather than by row, and each column (within each micro-partition) is stored together physically, which allows for better compression and improved read performance.
Understanding how the data is physically organized helps in identifying high-level performance bottlenecks by allowing us to visualize how a query might run: does it need to get data from lots of different columns and partitions (slow) or can we reasonably expect data to be co-located (fast)?
Data Ingestion
To get the most out of Snowflake’s compression, be mindful of how it will be fed into Snowflake storage from other sources.
If ingesting data from S3/cloud storage be thoughtful around the format. We found that zstd Parquet generates both the smallest files (cheap storage) and fastest ingestion (when using vectorized load).
See which columns are actually used and consider moving less frequently used columns to other tables – especially if that data has sensitive information that should have different retention rules. This way you can avoid unnecessarily reprocessing data.
Be careful of array types. They are often easier to store and query but query performance suffers. If there's a way of "exploding" the data to be in rows or lookup tables, you might be better off.
Lastly, take a close look at platform- and region-specific transfer pricing. Moving data across regions and between different platforms incurs additional costs compared to data moving within the same region and platform.
Optimizing Columnar Data Storage
Since Snowflake stores data by column, structural decisions go a long way. Here are some high-level improvements that can be done to keep Snowflake’s compression space-efficient:
Replace long strings (e.g. “United States”) with a numeric ID and lookup table (a “country_id” value of “US” maps to a lookup table “name” value of “United States”). This helps with query execution speed as well.
The bottom line is that Snowflake’s columnar storage benefits most from efficient table structuring and applying these strategies improves both compression efficiency and query performance, thereby reducing the overall cost regardless of plan, region, or whether it’s prepaid or pay-as-you-go.
Warehouse Sizes
Warehouses can be set to different sizes depending on the tasks they are responsible for. In our example above, we’re spending 1,920 credits/month on the Large ETL warehouse. Maybe there's an opportunity to reduce the warehouse during off-peak times when a large warehouse is over-sized. Alternatively, maybe queries will run slower but still be acceptable given the cost savings.
Snowflake clusters offer auto-scaling capabilities but they can be adjusted manually (or programmatically) if more optimization is needed. Adjusting warehouse sizes can be a quick way to save credits but making it too small can lead to slow or queued queries, so care should be taken.
Data Retention
A seemingly obvious improvement is to reduce how much is being stored - this might mean reducing duplication (e.g. with a lookup table) or clearing out old data or moving old data to a cheaper storage service like AWS S3, Iceberg, or Google Cloud Storage. That data can then be queried from Snowflake without having to import it. Snowflake also offers an “external tables” feature that allows you to store external storage metadata within Snowflake but the data itself in S3 or elsewhere.
A well-structured data retention policy balances cost, performance, and accessibility. The key is automating archival, using external tables for historical data, and monitoring storage usage to optimize costs.
These methods are simple on the surface but require careful implementation to ensure there are no side effects and any performance trade-offs are acceptable. Any long-term change like this should be modeled and their costs estimated before implementation.
Idle Time
There’s a startup and shutdown costs associated with warehouse usage. Idle warehouses are shut down automatically after a period of inactivity but they can also be shut down manually if they’re not expected to be used again for some time. One of our clients does exactly this because they have a predictable ETL workload, so turning the warehouse off after their tasks are done is an easy way for them to save on their bill.
Query Batching
Conversely to managing idle time, queries can be batched to minimize idle time. Since there’s a hidden cost associated with warehouses starting up and shutting down, queries can be batched to eliminate idle time, especially if warehouses are idle frequently without shutting down. It’s cheaper to run a warehouse at 100% capacity for an hour than 50% capacity for two hours.
Similarly, partitions are cached on the warehouse level, so if we have queries that read the same partitions, we can automatically speed queries up by running them on the same warehouse (assuming it’s not shutdown and spun back up in between queries).
Query Optimizations
Many of the topics covered above (especially in “Optimizing Columnar Data Storage”) improve query performance (and therefore reduce credit usage). Snowflake offers some additional features that can speed things up.
Materialized views are pre-computed results that speed queries up, but are re-calculated when data changes. There’s a clear tradeoff between speed and storage cost and cost of re-calculation (or “refresh cost”), so this approach is best when there are frequent reads that depend on seldom-changing data. MVs can be thought of as memoization.
Dynamic tables are a newer feature with some key differences. Instead of refreshing when data changes, they refresh at a given interval. Additionally, instead of storing the query result, dynamic tables store a full snapshot of the data.
In our work, however, we’ve found that these features are better on paper than in practice. As always, the best way to get meaningful insights is to test, test, and test.
For a more in depth comparison, take a look at the breakdown below:
Clustering keys allow you to physically partition rows of data, for example clustering by “date” improves performance when retrieving data in chronological order. By default, Snowflake inserts data randomly (due to how partitioning works without clustering keys), so this approach is great for large tables where queries scan too many partitions. Data can be re-clustered in the future as data is added, though doing so uses Compute credits, so make sure clustering is overall favorable beforehand!
As an example, consider a real-world example of a large table (let’s say it’s 500TB and contains 5 billion rows) that’s frequently filtered by order_date. Clustering by order_date can lead to dramatic results:
That’s over $90,000, or almost 85%, in annual savings –- more than enough for a few pizza parties! And remember, Capacity pricing can reduce compute costs further. Our friends at select.dev have written an article dedicated to clustering that has more details on the topic.
Summary
As you can see, there are a lot of levers to pull, each with its own pros and cons – as with any decision in software engineering. Previous history provides invaluable insight to these big decisions, and Twing Data can help you on your quest by letting you visualize historical usage and patterns.
In our experience, and as mentioned throughout this article, the best way to quantitatively measure any changes is to test and inspect the results. Twing Data would be happy to work with you to identify opportunities to optimize your datamart so you can have more pizza parties.