<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl" -->

---
title: Step by step: Hubspot connector from Fivetran to dlthub
description: A data engineer documents a step-by-step migration of a HubSpot connector and its 13 dbt models from Fivetran to dlt (dltHub). The process covers keeping the...
canonical: https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Step by step: Hubspot connector from Fivetran to dlthub | daily.dev
og:description: A data engineer documents a step-by-step migration of a HubSpot connector and its 13 dbt models from Fivetran to dlt (dltHub). The process covers keeping the...
og:url: https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl
og:image: https://api.daily.dev/og/posts/PQ45cmzTL.png
og:image:alt: Step by step: Hubspot connector from Fivetran to dlthub
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Step by step: Hubspot connector from Fivetran to dlthub

**[dltHub](https://daily.dev/sources/dlthub)** · 7 min read · 0 upvotes · 0 comments

## Summary

A data engineer documents a step-by-step migration of a HubSpot connector and its 13 dbt models from Fivetran to dlt (dltHub). The process covers keeping the old Fivetran/MotherDuck stack running as a reference, reverse-engineering Fivetran's undocumented schema transformations, rebuilding roughly three-quarters of the pipeline declaratively via dlt's rest-api-pipeline toolkit (with custom @dlt.resource functions for batch associations and fan-out endpoints), porting dbt models into dlt transformations with schema shims for Fivetran-only metadata columns, and a verification phase that surfaced an undocumented field rename and a routing exclusion in Fivetran's connector. The piece argues that vendor lock-in hides data reshaping logic, making migrations require careful row-count diffing rather than just code review.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://dlthub.com/blog/hubspot-connector-fivetran-to-dlthub>

## Questions this post answers

### How do I migrate a HubSpot connector and its dbt models from Fivetran to dlt?

Keep the Fivetran pipeline running as a reference while reverse-engineering its output schema, then rebuild in dlt using the rest-api-pipeline toolkit for declarative endpoints and custom @dlt.resource functions for batch associations and fan-out endpoints like pipelines/stages. Port each dbt model into a @dlt.hub.transformation function, add NULL/empty shims for Fivetran-only columns like _fivetran_synced, and verify by diffing row counts against the original mart.

_For teams planning a similar vendor-to-dlt migration, daily.dev surfaces practical writeups like this one._

### Why did my dlt HubSpot migration mart have a different row count than the Fivetran-based reference mart?

Two undocumented Fivetran connector behaviors caused the mismatch: the connector silently renamed HubSpot's pipeline property to deal_pipeline_id in the deal_history table, and it routed dealstage changes to a separate deal_stage table instead of including them in deal_property_history. Additional differences included ~200 extra rows from a newer sync window and timestamp storage as UTC instead of naive local time.

_Developers debugging pipeline migration mismatches can find grounded case studies like this via daily.dev._

### Which parts of a HubSpot API integration can't be handled by a declarative REST API pipeline like dlt's rest_api_source?

Batch associations (POST /crm/v4/associations/.../batch/read) require collecting parent IDs upfront and chunking them into shared request bodies, an aggregation pattern outside a per-record declarative source's model. Fan-out endpoints like pipelines/stages, properties/options, and email events/status-changes split one response across two output tables, which the declarative approach fails on outright, requiring custom @dlt.resource functions instead.

_Engineers evaluating declarative pipeline tools for tricky API shapes can track patterns like this on daily.dev._

## Similar posts on daily.dev

- [Consulting is becoming software.](https://daily.dev/posts/consulting-is-becoming-software--v5zxf18aj) · dltHub · 0 upvotes · 0 comments
- [migrate-fivetran-to-dlthub](https://daily.dev/posts/migrate-fivetran-to-dlthub-l1kqdgfch) · dltHub · 0 upvotes · 0 comments
- [4 YAML Files Instead of PySpark: How We Let Analysts Build Data Pipelines Without Engineers](https://daily.dev/posts/4-yaml-files-instead-of-pyspark-how-we-let-analysts-build-data-pipelines-without-engineers-kumvd7a9c) · Towards Data Science · 0 upvotes · 0 comments
- [Productionize Python ETL Scripts: Migrate to dlt & dltHub](https://daily.dev/posts/productionize-python-etl-scripts-migrate-to-dlt-dlthub-5ea79r3hn) · dltHub · 2 upvotes · 0 comments
- [dltHub Transformation is in public preview](https://daily.dev/posts/dlthub-transformation-is-in-public-preview-51ebvncrr) · dltHub · 1 upvotes · 0 comments

---

Tags: [#data-engineering](https://daily.dev/tags/data-engineering), [#etl](https://daily.dev/tags/etl)

[View this post on daily.dev](https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Step by step: Hubspot connector from Fivetran to dlthub","url":"https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl"},"datePublished":"2026-08-18T02:26:09.655Z","dateModified":"2026-08-18T02:26:43.487Z","description":"A data engineer documents a step-by-step migration of a HubSpot connector and its 13 dbt models from Fivetran to dlt (dltHub). The process covers keeping the...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/a9c48ae7252df830f734698c713e889f?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/a9c48ae7252df830f734698c713e889f?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"dltHub","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"dltHub","logo":"https://media.daily.dev/image/upload/s--lanGOBQH--/f_auto/v1734606584/logos/dlthub","url":"https://daily.dev/sources/dlthub"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"data-engineering,etl","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"dltHub","item":"https://daily.dev/sources/dlthub"},{"@type":"ListItem","position":3,"name":"Step by step: Hubspot connector from Fivetran to dlthub"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/step-by-step-hubspot-connector-from-fivetran-to-dlthub-pq45cmztl#faq","mainEntity":[{"@type":"Question","name":"How do I migrate a HubSpot connector and its dbt models from Fivetran to dlt?","acceptedAnswer":{"@type":"Answer","text":"Keep the Fivetran pipeline running as a reference while reverse-engineering its output schema, then rebuild in dlt using the rest-api-pipeline toolkit for declarative endpoints and custom @dlt.resource functions for batch associations and fan-out endpoints like pipelines/stages. Port each dbt model into a @dlt.hub.transformation function, add NULL/empty shims for Fivetran-only columns like _fivetran_synced, and verify by diffing row counts against the original mart. For teams planning a similar vendor-to-dlt migration, daily.dev surfaces practical writeups like this one."}},{"@type":"Question","name":"Why did my dlt HubSpot migration mart have a different row count than the Fivetran-based reference mart?","acceptedAnswer":{"@type":"Answer","text":"Two undocumented Fivetran connector behaviors caused the mismatch: the connector silently renamed HubSpot's pipeline property to deal_pipeline_id in the deal_history table, and it routed dealstage changes to a separate deal_stage table instead of including them in deal_property_history. Additional differences included ~200 extra rows from a newer sync window and timestamp storage as UTC instead of naive local time. Developers debugging pipeline migration mismatches can find grounded case studies like this via daily.dev."}},{"@type":"Question","name":"Which parts of a HubSpot API integration can't be handled by a declarative REST API pipeline like dlt's rest_api_source?","acceptedAnswer":{"@type":"Answer","text":"Batch associations (POST /crm/v4/associations/.../batch/read) require collecting parent IDs upfront and chunking them into shared request bodies, an aggregation pattern outside a per-record declarative source's model. Fan-out endpoints like pipelines/stages, properties/options, and email events/status-changes split one response across two output tables, which the declarative approach fails on outright, requiring custom @dlt.resource functions instead. Engineers evaluating declarative pipeline tools for tricky API shapes can track patterns like this on daily.dev."}}]}
```

