The world of automation is built on functions. From simple scripts to complex serverless architectures, we've become adept at writing code that performs a task. But as our systems grow, so does the complexity. Functions become entangled, boilerplate code multiplies, and what was once a clean piece of logic is now a maintenance nightmare. We need a new primitive, a better building block.
Enter the atomic action.
This isn't just a new name for a serverless function. It's a fundamental shift in how we think about, build, and compose our automated systems. It's the core principle behind building robust, scalable, and truly agentic workflows. It’s the key to turning your business logic into manageable, reusable Business-as-Code.
So, what exactly is an 'atomic action' on the .do platform?
Think of it as the smallest, indivisible unit of work in any process. It’s a self-contained, reusable function designed to perform a single task reliably and predictably.
Each action does one thing and does it well. It has defined inputs, a clear purpose, and produces a predictable output. This "single responsibility principle" isn't just good coding practice; it's the foundation for creating powerful workflow orchestration. By encapsulating any single, repeatable task as a self-contained Action, you can chain them together to create powerful, intelligent workflows and deliver Services-as-Software.
Defining an action is designed to be simple and intuitive. You focus on the core logic, and the platform handles the rest. Here’s how you would define an action.do to send a welcome email using TypeScript:
import { Action } from '@do-sdk/core';
// Define a new Action to send a welcome email
const sendWelcomeEmail = new Action({
name: 'send-welcome-email',
description: 'Sends a standardized welcome email to a new user.',
handler: async (inputs: { email: string; name: string }) => {
console.log(`Preparing to send email to ${inputs.email}...`);
// Logic to connect to an email service (e.g., SendGrid, SES)
// const emailSent = await emailService.send({
// to: inputs.email,
// subject: `Welcome, ${inputs.name}!`,
// body: 'We are so glad you joined us...'
// });
// Mock result for demonstration
const result = { success: true, messageId: `msg_${Date.now()}` };
console.log('Email sent successfully:', result.messageId);
return result;
},
});
// Execute the action via the .do SDK
async function run() {
const execution = await sendWelcomeEmail.run({
email: 'alex@example.com',
name: 'Alex',
});
console.log('Execution Result:', execution);
}
run();
In this example, the handler contains the pure business logic for sending an email. The name and description make the action discoverable and understandable by both humans and other automated agents.
This is a crucial distinction. While an Action might look like a function, it comes with powerful capabilities out-of-the-box. Actions on .do are supercharged functions.
A traditional serverless function is just a piece of code. You are responsible for everything around it: setting up logging, implementing retry logic, handling errors, managing versions, and figuring out how to trigger it.
An Action on .do is an opinionated, production-ready building block. It is automatically instrumented with:
Most importantly, Actions are designed from the ground up to be composed into larger agentic workflows, turning your library of functions into an interactive, manageable ecosystem of code.
A common question is, "Can an Action call other Actions?"
While technically possible, the power of this model lies in a clearer separation of concerns. While Actions are designed to be atomic, complex logic is best handled by orchestrating multiple Actions within a Workflow (e.g., a workflow.do file).
Think of it like LEGOs:
This approach promotes extreme modularity and reusability. Need to change your email provider? You only update the send-email action, and every workflow that uses it instantly benefits. This clear orchestration layer makes your automations easier to read, debug, and maintain.
The possibilities are virtually limitless. If you can script it, you can make it an Action. Common examples include:
By breaking down complex business processes into these small, atomic units, you create a powerful library of capabilities. This library becomes the engine for all your automations, enabling you to build faster, adapt to change quicker, and finally achieve true Business-as-Code.
Ready to move beyond serverless and start building the future of automation? Get started with action.do today.