Controlling Snowflake Cost When an ELT Tool Backfills Years of Data

Quick answer: An ELT tool's first sync loads all of a source's history at once, and even when the tool does not bill for that historical load, your Snowflake warehouse does. Give the tool its own loader warehouse with a fixed size and a single cluster, put a resource monitor and a statement timeout on it, and schedule large backfills deliberately. We learned this on a six-week project for a Series A SaaS company, where a three-year Stripe backfill used far more credits than expected.

Last updated: October 2026

Small companies adopt managed ELT tools because they remove the work of building connectors. The part that is easy to miss is that the first sync of every source is a bulk historical load, and it arrives at the warehouse all at once.


This article draws on a project for a 45-person B2B SaaS company, described in our SaaS analytics case study. Product data lived in PostgreSQL, billing in Stripe, support in Zendesk, marketing attribution in HubSpot and behaviour tracking in Mixpanel, and the head of engineering spent about three hours every Monday assembling a metrics email that was wrong roughly 30% of the time. Project details come from that engagement. The configuration examples are illustrative, written for this article.


Free historical loads still cost credits


We used Hevo Data to bring all five sources into Snowflake. Its pre-built connectors for Stripe, Zendesk, HubSpot and Mixpanel were each connected in under a day; Stripe took about two hours from setup to first data, including the historical backfill. That backfill loaded three years of invoice data in one go, and it used far more Snowflake credits than we had expected.


The cause is a split in who pays for what. Hevo's documentation says historical data ingestion is free, and its billable events are rows inserted or updated at the source after the pipeline is created. The compute that loads those historical rows into Snowflake is not free, because it runs on your warehouse. A tool that is cheap during its backfill can still produce the most expensive day of the month on the warehouse side.


Hevo's historical load is also all or nothing per pipeline. With Load Historical Data enabled, the entire table is fetched in the first run; disabled, only records written after the pipeline was created are loaded. For PostgreSQL there is no documented way to limit the history to a date range, so the choice is to load everything, skip particular objects, or load nothing historical.


Give the loader its own capped warehouse


Our fix was to set MAX_CLUSTER_COUNT to 1 on the warehouse Hevo loads through and accept slower initial loads in exchange for predictable cost. Capping clusters works because of how Snowflake scales. A standard warehouse keeps the size you give it; it does not resize itself. A multi-cluster warehouse, on Enterprise Edition, adds clusters when queries start to queue, which an ELT tool loading many tables in parallel can easily cause. Capping it at one cluster turns a burst of parallel loads into a queue, which takes longer and costs a known amount per hour.


A dedicated, capped loader warehouse with a monitor
CREATE WAREHOUSE IF NOT EXISTS elt_loader_wh
  WAREHOUSE_SIZE = 'SMALL'
  MIN_CLUSTER_COUNT = 1
  MAX_CLUSTER_COUNT = 1          -- queue instead of scaling out
  AUTO_SUSPEND = 60
  AUTO_RESUME = TRUE
  ENABLE_QUERY_ACCELERATION = FALSE
  STATEMENT_TIMEOUT_IN_SECONDS = 7200;

-- Resource monitors can only be created by ACCOUNTADMIN.
CREATE RESOURCE MONITOR IF NOT EXISTS elt_loader_monthly
  WITH CREDIT_QUOTA = 200
  FREQUENCY = MONTHLY
  START_TIMESTAMP = IMMEDIATELY
  TRIGGERS ON 75 PERCENT DO NOTIFY
           ON 100 PERCENT DO SUSPEND;

ALTER WAREHOUSE elt_loader_wh SET RESOURCE_MONITOR = elt_loader_monthly;

A few details make this setup safer:



Schedule the first sync of any large source for a quiet period, and tell whoever watches the bill before it starts.


Log-based CDC from PostgreSQL on RDS


Hevo's PostgreSQL connector uses logical replication by default, which on Amazon RDS means turning on rds.logical_replication. It is a static parameter, it cannot be changed in a default parameter group, and the change takes effect only after a reboot, so plan a brief maintenance window. In the project, this was a parameter group change and a reboot and nothing more.


Enable logical replication on RDS for PostgreSQL (AWS CLI)
# A custom parameter group is required; the default group cannot be modified.
aws rds modify-db-parameter-group \
  --db-parameter-group-name app-postgres-logical \
  --parameters "ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot"

aws rds reboot-db-instance --db-instance-identifier app-postgres

# Then, in psql, confirm:
#   SHOW rds.logical_replication;   -- on
#   SHOW wal_level;                 -- logical
#   GRANT rds_replication TO hevo_user;

Hevo's documentation for RDS lists further settings: max_replication_slots and max_wal_senders of 5, wal_sender_timeout of 0, backup retention of at least three days, and the rds_replication role for the Hevo user. AWS warns that logical replication increases WAL volume and that a replication slot nobody reads from can fill the instance's storage, so add a storage alarm at the same time. Two limits are also worth knowing: Hevo's standard pipelines cannot replicate from a read replica, and for teams created after Hevo's Release 2.21, log-based pipelines default to, and cannot go below, a 30-minute sync frequency.


Agree the metric definitions before writing SQL


The hardest part of the project was not technical. It was getting the CEO, the VP of Sales and the head of marketing to agree what churn means. We spent a full afternoon at a whiteboard before any dbt model was written, and that meeting saved weeks of back-and-forth later.



Each metric became a single dbt model with a YAML description that the whole team reviewed in a pull request before it went live. Our article on building an MRR movement model in dbt covers the modelling and testing in more depth.


A BI tool sized to the team


We evaluated Looker and Preset as well as Metabase, and chose Metabase. At 45 people, Looker's modelling layer would have been a second abstraction on top of dbt that the team did not need, and Metabase's SQL-first interface suited the engineers who would be its main users. It reads directly from the dbt models in Snowflake.


The Monday email is now automated and goes out at 6am. In current versions of Metabase this is a dashboard subscription, which can send by email or Slack on an hourly, daily, weekly or monthly schedule, with CSV, XLSX or PDF attachments. Metabase began phasing out its older Pulses feature, which some guides still describe, when it introduced subscriptions in version 0.38. The whole platform, from five disconnected sources to self-serve analytics, took six weeks.


Pranay Vatsal, Founder & CEO

Pranay Vatsal is the Founder & CEO of CelestInfo with deep expertise in Snowflake, data architecture, and building production-grade data systems for global enterprises.

Related Articles

Frequently Asked Questions

Q: Does Hevo charge for historical loads?

Hevo's documentation says historical data ingestion is free, and billable events are rows inserted or updated at the source after the pipeline is created. The Snowflake warehouse that loads the historical data still consumes credits, so backfills can still be expensive on the warehouse side.

Q: Can a Snowflake warehouse change size on its own?

A standard warehouse keeps the size you set unless something runs ALTER WAREHOUSE. Multi-cluster warehouses, on Enterprise Edition, add clusters of the same size when queries queue. Adaptive warehouses are the exception: on those, Snowflake handles sizing and scaling automatically.

Q: How do I cap Snowflake spend for an ELT tool?

Give the tool a dedicated warehouse with a fixed size, MAX_CLUSTER_COUNT = 1 and an explicit query acceleration setting, attach a resource monitor that notifies and then suspends at a credit quota, and set STATEMENT_TIMEOUT_IN_SECONDS on the warehouse.

Q: How do I enable logical replication on Amazon RDS for PostgreSQL?

Set the static parameter rds.logical_replication to 1 in a custom DB parameter group attached to the instance, then reboot. Afterwards, wal_level reports logical. The default parameter group cannot be modified.

Q: What replaced Pulses in Metabase?

Dashboard subscriptions. Metabase introduced them in version 0.38, began phasing out Pulses at the same time, and now describes Pulses as deprecated. Subscriptions send a dashboard by email or Slack on a schedule, with optional CSV, XLSX or PDF attachments.