Simple automations are powerful. A new user signs up, a welcome email goes out. A payment is received, an invoice is generated. These are the foundational blocks of an efficient system. But what happens when your process isn't a single step? What if a new user signup should trigger a welcome email, wait a day, check for user activity, and then add them to your CRM?
This is where simple A-to-B automation falls short. You need a way to create a sequential, stateful process—a chain reaction where one completed task reliably triggers the next.
Welcome to the world of chained workflows. With trigger.do, you can move beyond single triggers and build sophisticated, multi-step automations that mirror your most complex business logic. It's how you truly trigger anything and automate everything.
Breaking down a large, monolithic process into a series of smaller, connected workflows isn't just a different way to build; it's a better way.
So, how do you connect one workflow to the next? The secret lies in a special kind of trigger: the Custom Event.
You already know that a workflow needs a trigger to start. It could be an external event like a webhook from Stripe, a cron-based schedule, or a direct API call.
A Custom Event is a trigger that you fire from within your own application or, more importantly, from within another workflow. When one workflow finishes its job, its final action can be to emit a custom event. This event then acts as the starting pistol for the next workflow in the chain.
Workflow 1 (Triggered by Webhook) → Completes → Emits Custom Event → Workflow 2 (Triggered by Custom Event)
This simple pattern is the key to unlocking powerful, sequential automation.
Let's walk through a common and practical example: a multi-step user onboarding sequence.
Our goal:
We'll start with the code you might already be familiar with: a trigger that runs when a new user is created. The key addition is the last line, where we use a delay and then send a customEvent to kick off the next step.
import { trigger, customEvent } from "@trigger.do/sdk";
// Triggered when a new user signs up in your app
new trigger.Job({
id: "new-user-welcome",
trigger: onEvent("user.created"),
run: async (event, context) => {
// Action 1: Send the welcome email
await send.email({
to: event.payload.email,
subject: `Welcome, ${event.payload.name}!`,
body: "We're excited to have you join us.",
});
context.logger.info("Welcome email sent.", { userId: event.payload.id });
// Action 2: Wait 24 hours before the next step
await context.delay("24h");
// Action 3: Trigger the next workflow in the chain
await customEvent({
name: "onboarding.send-follow-up",
payload: event.payload, // Pass the user data along!
}).send();
return { success: true };
},
});
Now, we create a second workflow. This one isn't triggered by user.created, but by the custom event we just fired: onboarding.send-follow-up.
import { trigger, customEvent } from "@trigger.do/sdk";
// Triggered by the custom event from our first workflow
new trigger.Job({
id: "user-onboarding-follow-up",
trigger: onEvent("onboarding.send-follow-up"),
run: async (event, context) => {
context.logger.info("Running follow-up for user.", { userId: event.payload.id });
// Action 1: Send the follow-up email
await send.email({
to: event.payload.email,
subject: "Getting the most out of our app",
body: "Here are some tips to get you started...",
});
// Action 2: Trigger the final step
await customEvent({
name: "onboarding.add-to-crm",
payload: event.payload,
}).send();
return { success: true };
},
});
Notice how we're using the event.payload that was passed from the first workflow. The context is carried seamlessly between steps.
Finally, the third workflow listens for the onboarding.add-to-crm event and performs the final action of adding the user to an external service.
import { trigger } from "@trigger.do/sdk";
import { crm } from "@integrations/our-crm";
// Triggered by the custom event from our second workflow
new trigger.Job({
id: "user-onboarding-add-to-crm",
trigger: onEvent("onboarding.add-to-crm"),
run: async (event, context) => {
// Action: Call the CRM's API to create a new contact
await crm.contacts.create({
email: event.payload.email,
name: event.payload.name,
id: event.payload.id,
});
context.logger.info("User added to CRM.", { userId: event.payload.id });
return { status: "Onboarding complete" };
},
});
And just like that, you've built a robust, resilient, and maintainable multi-step automation. Each piece is simple, but together they form a complex and powerful chain reaction.
By leveraging custom events, you can chain together any number of workflows, creating dependable sequences for background jobs, AI agentic actions, user onboarding, data processing pipelines, and more. You're no longer limited to single-step automations. You can now build workflows that truly reflect the complexity of your business.
Ready to connect your digital world seamlessly? Get started with Trigger.do today and turn your simple events into powerful, multi-step automations.