Compose complex automation programs from modular workflows using synchronous sub-workflow calls, asynchronous platform event fan-out, and shared data stores.
The Case for Modular Workflows
As your automation practice matures, you will find that large monolithic workflows become difficult to read, test, and maintain. A single workflow handling lead capture, enrichment, CRM update, and welcome email becomes brittle — one failing step can block everything downstream, and debugging requires scrolling through dozens of steps to find the issue. Modular workflows solve this by decomposing a large process into smaller, independent units that each do one thing well. In Cotonity, you can chain these units together using three composition patterns: calling a child workflow synchronously with the Sub-workflow step, emitting a platform event that triggers sibling workflows asynchronously, or writing intermediate results to a shared data store that a downstream workflow reads on a schedule.
Sub-Workflow Calls (Synchronous Composition)
The Sub-workflow step lets you invoke another published workflow directly from within your current workflow and wait for its result before continuing. This is ideal when the output of the child workflow is needed to proceed — for example, calling an enrichment workflow that returns a completed contact object before you write the data to your CRM. To use it, add a Sub-workflow step, select the target workflow from the dropdown, and map the input fields your child workflow expects. When execution reaches that step, Cotonity starts a new execution of the child workflow, waits for it to complete, and returns its output into your data context. Sub-workflow calls count toward the parent workflow's total execution timeout, so design your child workflows to be fast or increase the parent's timeout budget accordingly.
Platform Events (Asynchronous Fan-Out)
When you do not need to wait for a downstream process to complete — or when multiple independent processes should react to the same event — publish a platform event instead of using a sub-workflow call. Add an Emit Event step at the point in your workflow where the event occurs, give the event a descriptive name (for example, 'lead.qualified' or 'order.shipped'), and include a payload with the relevant data. Any other workflow with a Platform Event trigger subscribed to that event name will start in parallel as soon as the event is emitted. This fan-out pattern keeps each downstream workflow completely independent: you can add, remove, or update a subscriber without touching the publisher. Use a consistent event naming convention — 'noun.past_tense_verb' — so your event catalogue stays readable as it grows.
Shared Data Stores for Loose Coupling
Sometimes the cleanest integration between workflows is not a direct call or event, but a shared data store. Workflow A writes enriched records to a Cotonity data table; Workflow B runs on a schedule, reads the new rows, processes them, and marks them as handled. This pattern is especially useful when Workflow A produces data at an unpredictable rate and Workflow B should process it in controlled batches. Cotonity's built-in Key-Value store and Data Tables are available as first-class step types, so no external database is required for straightforward cases. Use a 'processed_at' timestamp column to prevent double-processing: Workflow B queries only rows where 'processed_at' is null, and after successfully handling each row it updates that column with the current timestamp.