DataLane
4 min readFivetran

Fivetran MAR: The Invoice That Doubled, and the Credits You Still Pay

Monthly active rows surprise you, warehouse writes have their own bill, a custom extractor can beat a connector, and Fivetran still does not replace dbt.

By Dinesh Chandra

Illustrated overview of Fivetran MAR: The Invoice That Doubled, and the Credits You Still Pay
Table of contents

The Fivetran invoice landed at $18,400. The previous three months had been $4,100 to $4,600. Nobody had added a source. Someone had enabled Salesforce history tables on an existing connector because an analyst wanted field-level audit. Monthly active rows jumped. Snowflake credits for that destination jumped with them: Fivetran was merging wide history into the warehouse every 15 minutes. Two bills. One checkbox.

MAR is not “rows in the table.” It is distinct primary keys that Fivetran saw change in the billing month, with their rules for how history and multi-table connectors count. I model it before I turn a connector on. I did not, that month.

What actually increments MAR

A quiet reference table that updates 200 keys a month is cheap. A chatty events table, or history enabled on every Salesforce object, is how you discover pricing. Re-syncs after a schema change can touch keys again. I treat a full re-sync as a budget event, not a click.

flowchart LR
  src["SaaS / DB"] --> ft["Fivetran"]
  ft -->|"MAR invoice"| bill1["Fivetran bill"]
  ft --> wh["Warehouse writes"]
  wh -->|"compute + storage"| bill2["Credits / slots"]
  wh --> raw["Raw / staging"]
  raw --> dbt["dbt models"]

Two meters. The connector fee and the warehouse write. History tables hit both.

-- Destination-side: what did Fivetran write yesterday?
-- Snowflake example; adjust to your account usage views.
SELECT
    table_name,
    sum(row_count) AS rows_approx,
    max(last_altered) AS last_altered
FROM snowflake.account_usage.tables
WHERE table_schema = 'FIVETRAN_SALESFORCE'
  AND deleted IS NULL
GROUP BY 1
ORDER BY 2 DESC
LIMIT 30;

-- Volume band on a sync-critical table (same idea as Airbyte).
SELECT count(*) AS rows_24h
FROM raw.salesforce.opportunity
WHERE _fivetran_synced >= dateadd('hour', -24, current_timestamp());

I page if rows_24h is zero on a weekday or 10× the 30-day median. A successful connector with zero destination rows is the same silent outage as Airbyte’s green check.

Warehouse credits: Fivetran uses a warehouse you sized. Fifteen- minute syncs on a Large, all day, are a second invoice. I pin a dedicated Small/Medium, auto-suspend of 60 seconds, and I do not share it with dbt. dbt incremental models should not fight the loader for slots — see incremental models.

Custom extractor versus connector

For long-tail SaaS (support tools, HRIS, a survey product) I buy the connector. Engineer-hours to chase pagination and OAuth expire faster than MAR. For one Postgres that already has CDC habits, I price Debezium against MAR at peak keys. At 80 million active keys a month, we moved that source off Fivetran and kept Fivetran for the SaaS tail. The invoice became explainable.

A Python extractor I own is cheaper only if I also own retries, schema drift, and on-call. I have built three. Two were a mistake. The third replaced a connector that re-synced 12 million keys after every nested JSON change.

You still need dbt

Fivetran transformations are not a metrics layer. I leave them off. Raw tables get _fivetran_deleted and _fivetran_synced. Silver interprets those flags. Soft deletes that disappear in a hard DELETE break incrementals. Mixing “net ARR” into the connector is how you cannot test grain in CI.

-- Silver: honor the delete flag. Do not hard-delete in raw.
SELECT
    id,
    amount,
    stage_name,
    _fivetran_synced AS synced_at,
    _fivetran_deleted AS is_deleted
FROM raw.salesforce.opportunity
WHERE _fivetran_synced >= dateadd('day', -3, current_date());

I estimate MAR in the connector PR the same way I estimate a warehouse size: last month’s distinct keys, times history if enabled, plus a 30 percent buffer for a re-sync. If I cannot write that number, I do not enable the table.

Pitfalls

History on every object “for audit.” Audit two objects in dbt snapshots. History on forty objects is an MAR event and a credit event. The checkbox is not free.

Sharing the Fivetran warehouse with dbt. Loader MERGE and model MERGE queue each other. Pin a dedicated warehouse, auto-suspend 60 seconds, and keep it off the BI route.

A full re-sync on Friday afternoon. Distinct keys all count again. Schedule it, warn finance, and watch destination credits the same hour.

Building a custom extractor for a long-tail SaaS. You will rebuild OAuth and pagination. Buy the connector. Save custom work for the one source that dominates the invoice.

Treating sync success as freshness. Zero destination rows on a weekday is the outage. Count them.

Enabling a connector in prod to “see the schema.” Use a dev destination and a table allow-list. The first sync against prod is when MAR starts. I have paid for a week of exploration that should have been a sandbox.

I keep a spreadsheet with connector, estimated MAR, history on/off, destination warehouse size, and owner. Ugly. It is how $18k becomes a line item instead of a surprise. Schema diffs still go to the same owner — a silent column type change is a contract break, not a Fivetran feature. I review that sheet when the invoice arrives, not a month later.

The history-table incident: we disabled history on objects we did not use for SCD2, moved the two objects we did need to a dbt snapshot, and put a monthly MAR estimate in the connector PR template. $18k was a surprise. The next checkbox will not be. Fivetran is a good extractor. It is a bad place to hide a second warehouse and a worse place to hide the model.

Share this post:X / TwitterLinkedIn

Enjoyed this post?

Get the next one in your inbox — one email a week, no spam.

Newsletter signup is not live yet. Use the contact form if you want to be notified.

↑↓ navigate openesc close