---
name: hubspot-workflows-design
slug: hubspot-workflows-design
description: This skill should be used when the user asks to "design HubSpot workflows", "build workflows in HubSpot", "automate in HubSpot", "set up HubSpot automation", "create a workflow in HubSpot", "design lead routing in HubSpot", "build a nurture workflow in HubSpot", "automate lifecycle stages in HubSpot", "fix HubSpot workflows", or any variation of designing, building, or troubleshooting workflow automation in HubSpot for B2B SaaS.
category: general
---

# HubSpot Workflows Design

HubSpot workflows automate repeatable actions: setting properties, sending emails, creating tasks, routing leads, updating lifecycle stages, and triggering notifications. Every B2B SaaS HubSpot instance needs 10-20 core workflows. Beyond 50 active workflows, maintenance becomes a full-time job. Design for clarity and restraint.

The principle: a workflow should do one job. If the workflow description takes more than one sentence, it's probably doing too much. Split it.

## Workflow Types

HubSpot supports 5 workflow types based on the object that triggers them.

| Type | Triggers on | Use for | Available on |
|------|------------|---------|-------------|
| Contact-based | Contact property change, form submission, list membership, page view | Lifecycle transitions, lead routing, nurture, scoring actions | All paid tiers |
| Company-based | Company property change, associated contact actions | ABM workflows, account-level automation | Professional+ |
| Deal-based | Deal property change, deal stage change | Sales process automation, notifications, task creation | Professional+ |
| Ticket-based | Ticket property change, ticket creation | Support automation, SLA alerts | Service Hub Professional+ |
| Custom object-based | Custom object property change | Enterprise-specific automation | Enterprise only |

**Type selection rules:**
- Use contact-based workflows for anything about a person: lifecycle stage, lead routing, nurture enrollment, scoring
- Use deal-based workflows for anything about a deal: stage-change notifications, task creation per stage, stale-deal alerts
- Use company-based workflows for account-level actions: ABM tier assignment, target account flagging, company lifecycle updates
- Don't use contact-based workflows to track deal-level processes. "Contact filled out a form" is contact-based. "Deal moved to proposal stage" is deal-based. Mixing them creates maintenance nightmares

---

## The 15 Essential Workflows for B2B SaaS

### Category 1: Lifecycle management (4 workflows)

**1. Lead → MQL promotion**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS Lead
  AND (HubSpot Score >= 50
       OR Contact submitted form "Demo Request"
       OR Page views contain "/pricing" >= 2 times)
Actions:
  1. Set Lifecycle Stage → MQL
  2. Set Lead Status → New
  3. Set property "MQL Date" → today
  4. Send internal notification to contact owner
Re-enrollment: OFF (once per contact)
```

**2. MQL → SQL promotion**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS MQL
  AND Lead Status IS "Qualified"
Actions:
  1. Set Lifecycle Stage → SQL
  2. Set Lead Status → New (reset for AE)
  3. Set property "SQL Date" → today
  4. Send internal notification to assigned AE
Re-enrollment: OFF
```

**3. Contact recycling**
```
Trigger: Contact-based
Enrollment: Lead Status IS "Unqualified" OR "Bad Timing"
  AND Lifecycle stage IS MQL OR SQL
Actions:
  1. Set Lifecycle Stage → Lead
  2. Set Lead Status → Recycled
  3. Set property "Recycle Date" → today
  4. Enroll in re-nurture email sequence (delay 30 days)
  5. Clear contact owner (returns to pool)
Re-enrollment: ON (contact can be recycled multiple times)
```

**4. Deal-based lifecycle sync**
```
Trigger: Deal-based
Enrollment: Deal stage changed
Actions:
  If deal stage = Closed Won:
    1. Set associated contacts' lifecycle stage → Customer
    2. Set associated company lifecycle → Customer
    3. Send internal notification to CS team
  If deal stage = Closed Lost:
    1. Set property "Loss Reason" (require on stage change)
    2. Set property "Lost Date" → today
    3. If loss reason IS "Bad Timing": enroll contacts in recycle flow
Re-enrollment: ON (multiple deals per contact possible)
```

### Category 2: Lead routing (3 workflows)

**5. New MQL routing (round-robin)**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS MQL
  AND Lead Status IS "New"
  AND Contact Owner IS empty OR IS "Unassigned"
Actions:
  1. Rotate among SDR team:
     - SDR A (33%)
     - SDR B (33%)
     - SDR C (34%)
  2. Set Contact Owner → assigned SDR
  3. Create task for assigned SDR: "Follow up with new MQL"
     Due: 1 hour from now
  4. Send Slack notification to assigned SDR
Re-enrollment: OFF
```

**6. Territory-based routing**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS MQL
  AND Lead Status IS "New"
  AND Country IS known
Actions:
  If/then branch:
    If Country IS US AND State IS CA, WA, OR:
      Set owner → AE West
    If Country IS US AND State IS NY, MA, CT:
      Set owner → AE East
    If Country IS GB, DE, FR:
      Set owner → AE EMEA
    Default:
      Set owner → SDR Pool (round-robin)
Re-enrollment: OFF
```

**7. Account-based routing (existing account)**
```
Trigger: Contact-based
Enrollment: Lifecycle stage changes to MQL
  AND Associated company has property "Company Owner" IS known
Actions:
  1. Copy "Company Owner" to "Contact Owner"
     (routes to existing account owner instead of round-robin)
  2. Create task for Company Owner: "New contact at owned account"
  3. Send Slack notification
Re-enrollment: OFF
```

### Category 3: Speed-to-lead (2 workflows)

**8. High-intent instant alert**
```
Trigger: Contact-based
Enrollment: Contact submitted form "Demo Request"
  OR Contact submitted form "Contact Sales"
  OR Contact viewed page "/pricing" >= 3 times in 1 session
Actions:
  1. Set Lifecycle Stage → MQL (if currently Lead)
  2. Route per routing workflow (#5, #6, or #7)
  3. Send Slack alert to #sales-alerts:
     "[Name] from [Company] just [action]. Follow up NOW."
  4. Create task: "Call [Name] - high intent"
     Due: 15 minutes from now
  5. Send auto-reply email: "Thanks for reaching out"
Re-enrollment: OFF
```

**9. MQL follow-up SLA escalation**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS MQL
  AND Lead Status IS "New"
  AND "MQL Date" IS more than 4 hours ago
Actions:
  1. Send notification to SDR manager:
     "MQL [Name] has been unworked for 4+ hours"
  2. If still "New" after 24 hours:
     Send escalation to VP Sales
  3. If still "New" after 48 hours:
     Reassign to backup SDR
Re-enrollment: OFF
```

### Category 4: Nurture (3 workflows)

**10. New lead nurture**
```
Trigger: Contact-based
Enrollment: Lifecycle stage IS Lead
  AND Lead Source IS NOT "Outbound" (don't nurture outbound prospects)
Actions:
  Email 1 (immediately): Welcome + top resource
  Delay 3 days
  Email 2: Case study relevant to their industry (use smart content)
  Delay 5 days
  Email 3: Webinar invite or product overview
  Delay 7 days
  Email 4: Soft CTA - "worth a quick look?"

  Goal: Lifecycle stage changes to MQL (exit workflow on conversion)
Re-enrollment: OFF
```

**11. Recycled lead re-nurture**
```
Trigger: Contact-based
Enrollment: Lead Status IS "Recycled"
  AND "Recycle Date" IS more than 30 days ago
Actions:
  Delay 30 days (cooling-off period)
  Email 1: New content or product update (not the same content they saw before)
  Delay 14 days
  Email 2: Industry benchmark or peer story
  Delay 14 days
  Email 3: Soft re-engagement: "Anything changed on [original pain point]?"

  Goal: Contact reaches MQL score threshold (exit and re-promote)
Re-enrollment: ON (can re-enter if recycled again)
```

**12. Post-demo no-show recovery**
```
Trigger: Contact-based
Enrollment: Meeting outcome IS "No Show"
  AND Lifecycle stage IS SQL OR Opportunity
Actions:
  Email 1 (immediately): "Missed you today - here's the recording/recap"
  Delay 2 days
  Email 2: "Still interested? Here are 3 times that work"
  Delay 5 days
  Email 3: "Should I close the loop?"

  If no response after all 3: Set Lead Status → "Bad Timing"
Re-enrollment: ON (per meeting, not per contact)
```

### Category 5: Deal management (2 workflows)

**13. Stale deal alert**
```
Trigger: Deal-based
Enrollment: Deal stage IS NOT Closed Won or Closed Lost
  AND Last activity date IS more than 14 days ago
Actions:
  1. Send notification to deal owner:
     "Deal [Name] has had no activity in 14 days. Update or close."
  2. Create task: "Update stale deal [Name]"
     Due: 2 days from now
  3. If no activity after 7 more days (21 total):
     Send escalation to sales manager
Re-enrollment: ON (re-triggers if deal goes stale again)
```

**14. Deal stage task creation**
```
Trigger: Deal-based
Enrollment: Deal stage changed
Actions:
  If/then by stage:
    Discovery → Create task: "Complete discovery call prep"
    Demo → Create task: "Send demo follow-up within 24 hours"
    Proposal → Create task: "Send proposal within 48 hours"
    Negotiation → Create task: "Review contract terms with legal"
    Verbal Commit → Create task: "Send contract for signature"
Re-enrollment: ON (triggers each time stage changes)
```

### Category 6: Data hygiene (1 workflow)

**15. Zombie deal cleanup**
```
Trigger: Deal-based
Enrollment: Close date IS in the past
  AND Deal stage IS NOT Closed Won or Closed Lost
Actions:
  1. Send notification to deal owner:
     "Deal [Name] has a close date in the past. Update or close."
  2. Delay 7 days
  3. If still open with past close date:
     Set deal stage → Closed Lost
     Set loss reason → "Stale - Auto-closed"
     Send notification: "Deal [Name] auto-closed as stale"
Re-enrollment: OFF
```

---

## Workflow Design Rules

### Naming convention

Use a consistent format: `[Category] - [Object] - [Action]`

**Examples:**
- `Lifecycle - Contact - Lead to MQL Promotion`
- `Routing - Contact - New MQL Round Robin`
- `Nurture - Contact - New Lead Drip`
- `Deal Mgmt - Deal - Stale Deal Alert`
- `Hygiene - Deal - Zombie Cleanup`

**Naming rules:**
- Category prefix makes workflows sortable and scannable in the workflow list
- Include the object type. "Lead to MQL" is ambiguous. "Contact - Lead to MQL" is clear
- Never name a workflow "Test" or "Copy of [other workflow]." Rename before activating

### Enrollment and re-enrollment

| Scenario | Re-enrollment setting | Why |
|----------|----------------------|-----|
| Lifecycle promotion (Lead → MQL) | OFF | A contact should only be promoted once per journey |
| Lead routing | OFF | Route once. Don't re-route on every property update |
| Nurture sequence | OFF (typically) | Don't re-enroll someone in the same drip they already completed |
| Recycling | ON | A contact can be recycled multiple times from different stages |
| Stale deal alert | ON | A deal can go stale, get updated, and go stale again |
| Deal stage tasks | ON | Tasks should fire each time the stage changes |

### If/then branches

- Keep branches to 3-5 max per workflow. Beyond 5, create separate workflows
- Always include a default/else branch. Contacts that don't match any branch should still get handled (even if the action is "do nothing and log it")
- Name each branch. "Branch 1" is unreadable. "US East Territory" is clear

### Delays

- Use "Business days" for sales-related delays. A 3-day delay on Friday fires Monday, not Sunday
- Don't chain more than 5 delays in one workflow. Long sequences with many delays are hard to debug and maintain. Use HubSpot sequences (separate feature) for multi-step email cadences
- Test delay timing by enrolling a test contact and watching the timeline

---

## Workflow Maintenance

### Monthly review checklist

- [ ] Count active workflows. If > 50, audit for duplicates and consolidation
- [ ] Check workflow errors (Settings → Workflows → Errors). Fix any enrollment or action failures
- [ ] Review enrollment counts. Workflows with 0 enrollments in 30 days may be obsolete
- [ ] Check for conflicting workflows (two workflows setting the same property to different values)
- [ ] Verify notification recipients are still on the team (people leave, workflows keep notifying)
- [ ] Review suppression lists. Contacts in suppression should be there intentionally

### Workflow documentation

For every active workflow, maintain a one-line entry in a shared doc:

```
| Workflow name | Object | Purpose | Owner | Last reviewed |
|--------------|--------|---------|-------|---------------|
| Lifecycle - Contact - Lead to MQL | Contact | Promotes leads to MQL on score threshold | RevOps | 2026-04-01 |
```

---

## Workflow Limits and Gotchas

| Gotcha | What happens | How to avoid |
|--------|-------------|-------------|
| Workflow loops | Workflow A sets a property that triggers Workflow B, which sets a property that triggers A again | Add enrollment conditions that prevent re-triggering. Check for circular dependencies before activating |
| Rate limits | HubSpot processes ~100 workflow actions per 10 seconds per portal. High-volume workflows queue | Don't enroll large lists (10K+) in instant workflows. Use scheduled drip enrollment |
| Suppression exhaustion | A contact hits the suppression list and blocks all future enrollment in that workflow | Use separate workflows per suppression need instead of one giant workflow with suppression |
| Association quirks | Deal-based workflows can't directly update contact properties without a "copy property" action or custom code | Use "Copy to associated contact" actions or Operations Hub custom code |
| Workflow goal vs unenrollment | Goal = exit condition (contact converted). Unenrollment = removed from workflow for a different reason | Use goals for positive outcomes (became MQL). Use unenrollment for negative outcomes (opted out) |
| Backdated data | Changing enrollment criteria on an existing workflow doesn't retroactively enroll contacts that already matched | To catch historical contacts, use "Enroll existing contacts" option when editing enrollment |

---

## Anti-Pattern Check

- 80+ active workflows with no naming convention. Unmanageable. Consolidate to 15-25 core workflows. Name with category prefix
- One workflow doing 6 things. A workflow that routes leads, sets lifecycle stage, sends a nurture email, creates a task, and updates a custom property is unmaintainable. Split into separate single-purpose workflows
- Re-enrollment ON for lifecycle promotions. A contact should not be promoted from Lead to MQL every time their score changes. Once promoted, the workflow should not re-fire. Set re-enrollment OFF
- No default branch in if/then logic. Contacts that don't match any condition silently fall out of the workflow. Always handle the "else" case, even if the action is just "set a flag for review"
- Notification workflows with no SLA. "Notify SDR about new MQL" without a follow-up escalation is a notification that gets ignored. Add an escalation step if no action is taken within the SLA
- Test contacts left in production workflows. Test contacts trigger real notifications, real tasks, and real email sends. Remove test contacts from workflows before going live. Use a test portal when possible
- Workflows modifying the same property from different triggers. Workflow A sets lead status to "New" and Workflow B sets it to "In Progress" based on different triggers. When both fire on the same contact, the result is unpredictable. Consolidate property updates into one workflow with branching
- No workflow documentation. When the person who built the workflows leaves, nobody knows what they do. Document every active workflow in a shared sheet with purpose, owner, and last review date