Business processes are rarely a straight line. A simple A → B workflow might work for basic tasks, but real-world scenarios involve decision points, dependencies, and the need for efficiency. They branch, they run tasks in parallel, and they require a sequence of steps to be executed flawlessly. Trying to manage this complexity with a patchwork of brittle scripts and cron jobs is a recipe for frustration and failure.
This is where workflow orchestration comes in. It’s the art and science of coordinating individual tasks to execute a larger, more complex business process.
At action.do, we believe the foundation of any robust workflow is the Atomic Action—a single, indivisible, and reliable unit of work. But their true power is unlocked when you start combining them. In this post, we'll explore the three fundamental patterns for building advanced, reliable automations: chaining, branching, and parallelizing.
Before we build a complex structure, we need to trust our building blocks. In the .do platform, an atomic action is a self-contained task like 'send an email' or 'update a CRM record'. It's designed with a simple guarantee: it either succeeds completely, or it fails cleanly without any side effects.
This atomicity is crucial. When you start connecting dozens of these actions, you can be confident that a failure in one step won't leave your entire system in a weird, inconsistent state. With this reliable foundation, we can confidently move on to orchestration.
Chaining is the most straightforward orchestration pattern: Action A must complete successfully before Action B can begin. The output of one action often becomes the input for the next, creating a logical, sequential flow.
Use Case: A classic user onboarding workflow.
With .do, you define this sequence as a single, auditable workflow. The platform ensures that the welcome email is never sent if the user record fails to be created.
// A conceptual .do Workflow definition
import { Workflow, client } from '@do-sdk/core';
const onboardingWorkflow = new Workflow({
name: 'user-onboarding',
run: async ({ inputs }) => {
// 1. Chain: Actions run one after another
const { userId } = await client.action('create-user-record').invoke({
email: inputs.email,
name: inputs.name
});
// The output of the first action is passed to the next
await client.action('send-welcome-email').invoke({
userId: userId
});
await client.action('provision-initial-resources').invoke({
userId: userId
});
}
});
Business logic is full of "if this, then that" scenarios. Branching allows your workflow to take different paths based on the data it's processing or the outcome of a previous action.
Use Case: An e-commerce order fulfillment process.
This ensures you never charge a customer for an out-of-stock item. On the .do platform, this conditional logic is just standard code, making it incredibly intuitive for developers while providing a fully auditable trail of which path was taken and why.
// A conceptual .do Workflow definition
const orderFulfillment = new Workflow({
name: 'order-fulfillment',
run: async ({ inputs }) => {
const { inStock } = await client.action('check-inventory').invoke({
productId: inputs.productId
});
// 2. Branch: Use simple if/else for conditional logic
if (inStock) {
await client.action('process-payment').invoke({ orderId: inputs.orderId });
await client.action('ship-order').invoke({ orderId: inputs.orderId });
} else {
await client.action('send-backorder-notification').invoke({
orderId: inputs.orderId,
email: inputs.customerEmail
});
}
}
});
Why wait for tasks to finish one by one if they don't depend on each other? Parallelization, or "fan-out," is the pattern of executing multiple actions at the same time to dramatically speed up your workflows.
Use Case: Post-signup tasks that can happen all at once.
Once a new user's record is created, you might need to:
None of these tasks depend on the others. Running them in parallel means the entire process finishes as fast as the single longest-running action, not the sum of all of them.
// A conceptual .do Workflow definition
const postSignupFanOut = new Workflow({
name: 'post-signup-fan-out',
run: async ({ inputs }) => {
const { userId } = inputs;
// 3. Parallelize: Run independent actions concurrently
await Promise.all([
client.action('send-welcome-email').invoke({ userId }),
client.action('update-crm-record').invoke({ userId }),
client.action('notify-sales-team-on-slack').invoke({ userId })
]);
return { status: 'All post-signup tasks initiated.' };
}
});
The .do platform handles the complexity of running these jobs concurrently, managing resources, and handling errors for each branch independently.
The true power of this model emerges when you combine these patterns. A real-world agentic workflow for document processing might look like this:
This complex, multi-step process is defined as a single, manageable, and observable piece of code. You can see the entire flow, understand its logic, and trust its execution, because it's built on a foundation of reliable, atomic building blocks.
Ready to move beyond simple scripts and build powerful, scalable, and auditable business workflows? Define, execute, and manage your first atomic action on action.do today.