In today's complex business environment, your data isn't in one place. It's scattered across production databases, third-party SaaS platforms like Salesforce and Stripe, internal microservices, and marketing analytics tools. This data fragmentation creates a massive challenge for automation: every new agentic workflow requires custom, brittle integration code just to fetch the information it needs to run. The result? Repetitive work, slow development cycles, and fragile automations that break when a data source changes.
What if you could create a single, unified layer to access all your business data? A layer where fetching a "customer's subscription status" is a single, reusable command, regardless of whether that data lives in a PostgreSQL database, a Stripe account, or both.
Introducing data.query.do—the definitive data access layer for your agentic workflows.
At its core, a data.query.do is an atomic, reusable component that defines how to fetch and shape a specific piece of business data. Think of it as a super-powered, version-controlled API endpoint for your internal data. It encapsulates the logic needed to connect to one or more data sources, retrieve information, and return it in a clean, predictable structure.
Just as action.do provides atomic units for work, data.query.do provides atomic units for information. It allows you to abstract away the complexity of your data landscape, enabling your workflows to operate on a higher, more strategic level.
This approach is built on three key principles:
Creating a data.query is as simple as defining any other component on the .do platform. You specify its inputs and write a handler function that contains the logic for fetching and transforming the data.
Let's imagine you want a single, unified view of a user that combines their profile from your local database with their subscription status from Stripe. Here's how you'd define it:
import { Do } from '@do-platform/sdk';
// Initialize the .do client with your API key
const-do = new Do(process.env.DO_API_KEY);
// Define a new data query to get a unified user profile
const getUnifiedUserQuery = await-do.data.create({
name: 'get-unified-user-profile',
description: 'Fetches user data from a Postgres DB and their subscription from Stripe.',
inputs: {
userId: 'string',
},
handler: async (inputs) => {
// 1. Fetch base profile from internal database
const userProfile = await db.users.find({ id: inputs.userId });
// 2. Fetch subscription status from Stripe using their email
const stripeCustomer = await stripe.customers.list({ email: userProfile.email, limit: 1 });
const subscriptionStatus = stripeCustomer.data.length > 0 ? 'active' : 'inactive';
// 3. Return a unified, structured object
return {
id: userProfile.id,
name: userProfile.name,
email: userProfile.email,
subscription: subscriptionStatus,
createdAt: userProfile.createdAt
};
}
});
console.log('Data Query created:', getUnifiedUserQuery.id);
With this data.query defined, any other part of your system—from a billing action.do to a customer support workflow.do—can get this unified profile with a single, simple call, without ever needing to know about the underlying database or Stripe API.
Integrating data.query fundamentally changes how you build automations, making them simpler, more robust, and more scalable.
Your action.do handlers become dramatically cleaner. Instead of being bogged down with data-fetching boilerplate, they can focus exclusively on their core task.
Before data.query: An action to send a "welcome" email contains complex logic to fetch user details.
After data.query: The action becomes trivial.
// Inside an action.do handler
handler: async (inputs) => {
// Simply run the pre-defined data query
const user = await-do.data.run('get-unified-user-profile', { userId: inputs.userId });
// Focus on the action's single responsibility
await email.send({
to: user.email,
subject: 'Welcome to the platform!',
body: `Hi ${user.name}, we're glad you're here.`
});
return { emailSent: true };
}
Data sources are not static. APIs get deprecated, database schemas evolve, and services get migrated. With a traditional approach, such a change would require you to find and update every single workflow that touches that data source.
With data.query, the logic is centralized. If you migrate from Stripe to a different payment processor, you only need to update the get-unified-user-profile query handler. All the dozens or hundreds of workflows that depend on it will continue to work seamlessly, with no changes required.
The .do platform treats your data.query components as first-class, managed entities. This means you get powerful features out of the box:
For too long, business automation has been shackled by the complexity of accessing data. Building intelligent, agentic workflows requires a new foundation—one where data is treated as a first-class, composable resource.
data.query.do is that foundation. It's the unified data layer for the modern, automated enterprise. By abstracting your data sources into atomic, reusable queries, you unlock a new level of speed, reliability, and scale for your Business-as-Code.
Stop writing boilerplate API clients and SQL statements in every function. Start defining your business data as executable components with data.query.do.