← All Insights
HubSpotdata-architectureRevOpsmethodology

HubSpot portfolio-to-deal association: three ways to wire it, and the one that actually works

Native primitives before report embeds before custom UI extensions. The ordering holds in roughly every HubSpot architecture call we run.

When portfolio data has to live alongside deal records in HubSpot, the schema almost never lines up the way the relationship manager expects. The portfolio sits on the contact, the deal sits one hop away, and the native association table on the deal record quietly returns nothing. Three ways to wire it. Two feel cleaner. The one that holds up in production accepts a noisier surface in exchange for never losing a record. Native first, report embed second, custom UI extension last.

Why this matters now

Financial-services and PE-style data models are showing up inside HubSpot more often than they used to, and the data architecture rarely catches up to the operating model in the first build. McKinsey's reference work argues the modern stack succeeds or fails on how well its pillars are connected, not on the depth of any single pillar: agility comes from the joins, not the objects (Castro, Machado, Roggendorf, Soller, "How to build a data architecture to drive innovation: today and tomorrow," McKinsey Digital, June 2020). Same logic inside a CRM. A clean portfolio object and a clean deal object are necessary but not sufficient, the join is where the operating model lives, and getting it wrong is the failure mode that hides in plain sight for two quarters.

The current state of the system

Before recommending anything, reconstruct what the schema actually does. In a typical wealth-platform setup, the relevant objects are roughly four: Contact, Deal, a custom Portfolio object, and Company. The investor is a Contact. The active sales conversation: onboarding, top-up, mandate change, is a Deal. The Portfolio is a custom object, one or many per investor, carrying the financial state, AUM bucket, mandate type, funded date, status.

Associations usually look like this. Contact ↔ Portfolio is the source-of-truth association: every portfolio is owned by exactly one investor contact. Contact ↔ Deal is direct, the primary contact on the deal is the investor. Deal ↔ Portfolio is where it gets interesting. In most builds we inherit, this association either does not exist as a native primitive, or it exists but is populated only manually.

Which means when a relationship manager opens a deal and looks at the native association card for portfolios, they see nothing, even though the investor demonstrably has three portfolios one hop away. The data is in the system. The deal record cannot see it.

Three options for wiring portfolio onto the deal

Three viable options, each with a different complexity profile and failure mode. The right one is almost always the most native that meets the constraint.

Option 1, Native association table on the deal

The cleanest answer in principle. HubSpot supports a direct Deal ↔ Portfolio association, turn it on, add the association card to the deal record sidebar, and the relationship manager sees the portfolios on the deal page. No reports, no extensions, no dev work. Native primitives all the way down.

The catch, this option only surfaces records that are directly associated. A portfolio living on the contact but not explicitly associated to the deal will not appear, there is no second-level association traversal in the native sidebar card. So the native association table is the right surface, but only if something is responsible for populating it. Left alone, it will be empty more often than not.

Option 2, Report-table embed on the deal record

Build a single-object or cross-object report that pulls portfolios filtered by "primary contact on this deal," then embed it on the deal record. This works. Uses native reporting, traverses the contact hop, no custom code.

The downsides are real. It reads as a report rather than a working surface, a relationship manager on a deal expects an association card with click-through, not a tabular list. Filter logic on embedded reports is constrained, and load behavior on the deal page is noticeably slower than a native association card. The right tool for executive overview dashboards, not for the surface a relationship manager works against fifty times a day.

Option 3, Custom UI extension

Build a HubSpot UI extension: a React component in the deal record sidebar, that queries portfolios via the API based on the deal's primary contact, renders them in a custom card, links each to the portfolio record. Maximum control. The relationship manager gets exactly the surface you want, with whatever filters, grouping, and visual hierarchy the workflow needs.

The cost is dev work, ongoing maintenance, and a deployment dependency for every change to the surface. UI extensions also lock the team into a different operating model, changes that would otherwise be a five-minute config edit now require a developer ticket. For most teams, the maintenance burden outweighs the polish. UI extensions are the right answer when no native or report-based path satisfies the constraint, not the first answer.

The recommendation

Use Option 1, native association table, and wire it with a workflow. At deal creation, enroll the deal in a workflow that auto-associates every portfolio attached to the deal's primary contact onto the deal itself. The deal record now shows the native association card, fully populated, with click-through to each portfolio.

The trade, some deals will surface four or five portfolios where the relationship manager only cares about one. That is fine. Better to have more than less. The relationship manager filters visually in two seconds; the alternative is a clean UI and a missing record, which is the worse failure mode every time. A missing record is invisible. A noisier card is obvious.

Two implementation details matter. First, re-run the workflow on contact-change events, not just creation, primary contacts get reassigned during onboarding, and the association set has to follow. Second, keep the deal-to-portfolio association labeled (not just present) so reporting can distinguish auto-associated from manually curated. The label is free; its absence becomes a debugging tax inside six months.

Pattern from the field

A EU-based wealth-management platform with a portfolio-of-portfolios data model came to us with the deal record showing zero portfolios for investors who manifestly had several. The team's instinct was Option 3, a UI extension, because a developer was available and the surface was visible to senior relationship managers. The actual fix was a six-step workflow built in an afternoon, trigger on deal creation and primary-contact change, look up portfolios on the primary contact, iterate, associate each with a labeled association, log the count to a deal property for QA. The team validated by reconciling deal-portfolio counts against contact-portfolio counts for the previous quarter's deals; once that matched, the workflow ran across the pipeline. No UI extension shipped. The native association card is the working surface, and it has stayed populated through two pipeline restructures.

Resolution, the playbook

If you are wiring portfolio (or any one-hop custom object) onto a deal record in HubSpot:

  1. Reconstruct the schema first. Confirm which objects exist, which associations are native, and where the source-of-truth association lives. Start with the join graph, not the recommendation.
  2. Enable the native deal-to-portfolio association. Add the association card to the deal record sidebar. Confirm it renders empty before wiring automation against it.
  3. Build the auto-association workflow. Trigger on deal creation and on deal primary-contact change. Iterate portfolios on the primary contact. Associate each to the deal with a labeled association so reporting can tell auto from manual.
  4. Accept the over-association tradeoff. Some deals will surface four or five portfolios; that is the correct behavior. The relationship manager filters visually. The alternative is a clean card and a missing record.
  5. Reconcile against the historical pipeline. Before going live, run the workflow against the last quarter's closed deals and reconcile portfolio count per deal against portfolio count on the primary contact. Mismatches are usually association-label gaps, not workflow logic.
  6. Log the count to a deal property. A simple integer, "associated portfolios at deal creation", gives the team a free debugging signal six months later.
  7. Reserve UI extensions for cases where the native path actually fails. If the workflow meets the constraint, ship it and move on. UI extension dev work is the option you reach for last, not first.

Where Checkpoint comes in

Most of the HubSpot architecture work we do at Checkpoint is exactly this shape, a custom-object schema that almost works, a relationship-manager surface that almost shows the right data, and a missing native association nobody wants to be the one to wire. The native primitives carry more weight than most teams credit them for. If portfolios, contracts, subscriptions, or any other one-hop custom object is silently missing from your deal records, the easier way of doing it is almost always the right one, and almost always the one to try first.

Sources

Harmeet Obhrai
Harmeet Obhrai
RevOps & GTM Systems

Seven years building revenue infrastructure for high-growth companies. Former Head of RevOps at SellerX (Amazon roll-up), where he led CRM strategy across 30+ brands and built a centralised HubSpot stack. GTM systems lead at Mercari, Foodji, and SS Realty. MBA (Quantic), BSc Economics (UCL & Columbia).

LinkedIn

Share this article