Skip to content

Commit 042b184

Browse files
Created workflows best practices (#13991)
* Created workflows best practices Wrote a doc with Workflows best practices. For now they're pretty basic, we can keep updating this doc as we migrate more of our campaigns. * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Update contents/docs/workflows/best-practices.mdx Co-authored-by: Edwin Lim <[email protected]> * Updated best-practices.mdx Updated based on Edwin's comments * Updated best-practices.mdx --------- Co-authored-by: Edwin Lim <[email protected]>
1 parent d835bab commit 042b184

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
title: Workflows best practices
3+
sidebar: Docs
4+
showTitle: true
5+
---
6+
7+
## Boundaries
8+
### Define clear triggers and avoid overlapping workflows
9+
10+
Use a single well-defined trigger per workflow (e.g. “user sign-up”, “purchase completed”, or a webhook), so the logic is clear. PostHog defines that every workflow starts with a trigger and end with an exit.
11+
12+
Avoid multiple workflows that respond to the same event and perform overlapping actions as this can cause duplicate messages or conflicting side-effects.
13+
14+
If you really need multiple workflows on the same event, consider whether a single workflow with [audience splits](/docs/workflows/workflow-builder#audience-splits)/branching logic would serve better.
15+
16+
### Minimize deduplication and side-effects
17+
18+
Don’t duplicate workflows that do essentially the same thing under slightly different triggers, which increases the risk of duplicate messages, conflicting updates, or unexpected user experience.
19+
20+
Avoid side-effects where possible. For example, don’t rely too heavily on property updates or event triggers inside a workflow, treat automations as eventual side-effects, not core business logic.
21+
22+
## Logic, branching, and timing
23+
### Limit complexity and keep logic as simple as possible
24+
25+
Use minimal branching and splits. Complex branching can make workflows hard to reason about.
26+
27+
<ProductScreenshot
28+
imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_33_41_2x_278ad5fae8.png"
29+
imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_33_41_2x_278ad5fae8.png"
30+
alt="Workflow complexity example"
31+
classes="rounded"
32+
/>
33+
34+
If you find yourself duplicating logic across multiple workflows, consider refactoring: either unify into one workflow or extract repeated logic into reusable sub-workflows (if supported), or design event properties in a way that triggers workflows cleanly.
35+
36+
### Use delays and conditions responsibly
37+
38+
Use delay steps (e.g. “wait 2 days”) or conditional logic only when necessary. Overuse can lead to unpredictable states, e.g. if user attributes change during the delay, or if event data evolves.
39+
40+
Keep records/logs where possible, especially for later debugging (e.g. knowing that a user was “waiting in step N of workflow X”).
41+
42+
### Design for fallback and safe defaults
43+
44+
For actions that send messages or update user data: ensure that if some data is missing (e.g. user email, user property) the workflow safely skips or uses defaults rather than failing or sending bad messages.
45+
46+
<ProductScreenshot
47+
imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/error_handling_28a45d2ecf.png"
48+
imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/error_handling_28a45d2ecf.png"
49+
alt="Error handling in workflows"
50+
classes="rounded"
51+
/>
52+
53+
## Testing setups and delivery
54+
55+
### Ensure messaging channels are properly configured and tested
56+
57+
Before sending emails or other messages, [set up and verify your channels](/docs/workflows/configure-channels). For email: configure "from" name, from-address, and DNS (SPF/DKIM) to avoid spam/folder issues.
58+
59+
Use templating and personalization carefully (e.g. with placeholders like `{{ person.name }}`), but also verify that placeholders resolve and avoid sending messages with unresolved variables.
60+
61+
If sending to external channels (e.g. Slack, SMS, webhooks), treat them as equally important as email: ensure you have fallback or error handling logic (e.g. when a webhook endpoint fails).
62+
63+
### Test workflows in a safe environment or subset first (staging/small user group)
64+
65+
Before a full rollout: test with internal users or a small percentage of real users. Monitor delivery for emails and messages, event logs, user property updates, or other side-effects. Watch for unintended behavior:
66+
- multiple emails
67+
- loops (i.e. your workflow triggers events that retrigger the same workflow)
68+
- delays stacking up
69+
70+
## Observability and limits
71+
72+
### Monitor and log
73+
74+
Ensure that failures (e.g. email bounce, webhook error) are captured and surfaced. When facing a problem, check the “[Troubleshooting & FAQs](/docs/workflows/troubleshooting)” section for Workflows.
75+
76+
For long-running workflows (with delays), track user state (which step they are in), and provide a way to debug or abort if something goes wrong.
77+
Periodically review metrics: how many messages sent, how many workflows triggered, bounce/failure rate, etc.
78+
79+
<ProductScreenshot
80+
imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_38_35_2x_908da89b7a.png"
81+
imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_38_35_2x_908da89b7a.png"
82+
alt="Workflow monitoring and metrics"
83+
classes="rounded"
84+
/>
85+
86+
### Be mindful of costs and rate limits
87+
88+
PostHog plans to price Workflows based on the number of real-time destinations and monthly messages after beta. Design workflows to minimize unnecessary messages. For example, avoid sending multiple messages to the same user around the same event, and use batching or deduplication logic where possible.
89+
90+
Clean up unused/outdated workflows to reduce unnecessary triggers and costs.
91+
92+
## Maintainability
93+
94+
### Plan for maintainability: naming, versioning, cleanup
95+
96+
Give workflows descriptive names like `welcome_email_on_signup`, `drip_7_day_followup`, etc. Avoid ambiguous names like `workflow1`. Version your workflows when you make significant logic changes, or at least document changes in a changelog, so you know which version ran when.
97+
98+
When a workflow becomes obsolete (e.g. onboarding process changed, or a campaign ended), archive or delete it to avoid accidental triggering and reduce maintenance burden.
99+
100+
### Document workflows: what they do, why they exist, who owns them
101+
102+
For each workflow, maintain a short description: what triggers it, what it does, expected behavior, and owner/maintainer. Document assumptions (e.g. “this workflow only runs for paid users”, “email template X must exist”, “delay step must be at least 24h”). Onboard new team members with a “workflow map,” a high-level overview of all active workflows and their purposes.
103+
104+
105+
106+
107+
108+
109+

src/navs/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5151,6 +5151,12 @@ export const docsMenu = {
51515151
icon: 'IconDatabase',
51525152
color: 'blue',
51535153
},
5154+
{
5155+
name: 'Best practices',
5156+
url: '/docs/workflows/best-practices',
5157+
icon: 'IconStar',
5158+
color: 'red',
5159+
},
51545160
{
51555161
name: 'Resources',
51565162
},

0 commit comments

Comments
 (0)