Workflows
Workflow templates describe an automation as a node graph — triggers wired to steps — stored as JSON. This page walks the dev loop: scaffold a template, validate it, test it against a development runner, then deploy it to production with a hot-swap so live traffic isn't interrupted.
For CI/CD pipeline automation, see CI/CD integration.
Before you start. Workflow commands (except a local workflow validate) talk to the dcupl cloud, so they need project credentials — configure them once with dcupl config set (see Cloud Sync). A runner is the managed environment in the cloud that executes a deployed workflow. You deploy and test against a runner — list them with dcupl workflow runners list. The list also shows app-runners; only runners of type workflow-runner run workflows. The dev and prod runners on this page are example runner keys: nothing marks a runner as dev or prod. --runner takes a runner's uid or its runnerKey.
Runtime budgets are enforced at execution time. The defaults are 10s total per workflow, 5s per request node, and 500ms per script node (your project's plan can set other values). A node that exceeds its budget is terminated.
The dev loop
You edit a *.workflow-v3.json file locally, exercise it against a runner, and deploy it with a hot-swap.
scaffold from the example shape — no guessing: dcupl schemas get TemplateV3 --example --json | jq -r '.example' > my.workflow-v3.json
the agent / you edit my.workflow-v3.json, then validate: dcupl workflow validate --file my.workflow-v3.json --local-only — output: ✓ valid (0 warning(s))
find an available dev runner: dcupl workflow runners list --json | jq -c '.[]' — output: {"uid":"<dev-uid>","runnerKey":"dev","type":"workflow-runner","url":"<runner-url>","health":"ok"} {"uid":"<prod-uid>","runnerKey":"prod","type":"workflow-runner","url":"<runner-url>","health":"ok"} {"uid":"<app-uid>","runnerKey":"apps","type":"app-runner","url":"<runner-url>","health":"ok"}
test on the dev runner; input.json holds the request body, e.g. {"orderId":"123"}: dcupl workflow test --file my.workflow-v3.json --runner <dev-uid> --input input.json — output: Execution <executionId> — workflow <projectId>-import-products • trigger [ok, 1ms] → 1 item(s) • fetch [ok, 412ms] → 1 item(s) • map [ok, 3ms] → 1 item(s) • respond [ok, 2ms] → 1 item(s)
deploy to prod — waits for the hot-swap: dcupl workflow deploy --file my.workflow-v3.json --runner <prod-uid> --yes — output: ✓ deployed <projectId>-import-products (uid <uid>, v <hash>) — live ✓
1 · Scaffold & edit
Start from the example shape rather than a blank file, then wire up triggers and steps within the runtime budgets above. See Schemas for more on schemas get. Take the example field of the --json output: without --json, the command prints the schema's TypeScript source before the example, and the file is not valid JSON.
dcupl schemas get TemplateV3 --example --json | jq -r '.example' > my.workflow-v3.json Or scaffold a complete read-transform-write template with dcupl generate workflow --name <key>. In a workspace (it needs dcupl.config.json) it writes <key>.workflow-v3.json to workflows/ in your baseFolder (default dcupl/), which dcupl files push syncs; the file passes workflow validate --local-only as written. Set its dcuplFilesApiKey variable before you deploy it. See Scaffolding.
2 · Validate
Validate locally or against a runner's environment.
# Validate locally, no runner needed
dcupl workflow validate --file my.workflow-v3.json --local-only
# Validate against a specific runner's environment
dcupl workflow validate --file my.workflow-v3.json --runner <uid>3 · Find your runners
List them to pick a workflow runner to test on and one to deploy to.
dcupl workflow runners list # columns: uid, runnerKey, type, url, health
dcupl workflow runners get --id <uid>4 · Test on a dev runner
This deploys the template to the runner, then exercises it. A full run (without --node) needs a trigger-request node, or it stops with NO_REQUEST_TRIGGER: it calls that trigger with the first of its methods and the --input file as the body (not for GET), and prints the node-by-node trace. A trigger with auth needs no extra key: dcupl sends the trigger's own API key. When a node fails, the command prints the trace and exits 1 with WORKFLOW_RUN_ERROR. The schema example fetches https://api.example.com/products (the apiUrl variable), so point apiUrl at a real endpoint before you test it.
# --input takes a path to a JSON file (the request body), not inline JSON
echo '{"orderId":"123"}' > input.json
dcupl workflow test \
--file my.workflow-v3.json \
--runner <dev-uid> \
--input input.json--node <id> | Exercise a single node instead of a full run |
--input <path> | JSON file: the request body for a full run, or the inputData for --node |
--state <path> | JSON file: $state seed for --node |
--wait / --no-wait | Wait for the hot-swap before triggering (default on) |
--swap-timeout <ms> | How long to wait for the swap (default 30000) |
The test deploy is real.workflow test performs the same deploy as workflow deploy, just without its confirmation prompt (dcupl still validates the template before it deploys it): the template replaces whatever that runner serves under the same key, and it stays deployed after the run. Point --runner at a runner nothing depends on. The output doesn't print the deployed workflow's uid; to remove the test deployment, look it up with dcupl workflow list and run dcupl workflow undeploy --id <uid> --yes.
5 · Deploy to a prod runner
Deploy waits for the hot-swap to complete by default. Remove a deployed workflow with dcupl workflow undeploy --id <uid> --yes.
dcupl workflow deploy \
--file my.workflow-v3.json \
--runner <prod-uid> \
--yes| Flag | Default | Purpose |
|---|---|---|
--yes | — | Skip the confirmation prompt |
--wait | true | Wait for the hot-swap before returning |
--no-wait | — | Return immediately, don't wait for the swap |
--swap-timeout <ms> | 30000 | How long to wait for the swap |
Inspecting workflows
Once a workflow is deployed, these commands help you check its state and debug runs. To debug a failed run, find it in the history, then trace it node by node.
| Command | What it shows |
|---|---|
dcupl workflow list | All workflows |
dcupl workflow get --id <uid> | A workflow's details |
dcupl workflow template --id <uid> | Deployed template — drift check vs. the runner |
dcupl workflow status --id <uid> | Live status |
dcupl workflow history --id <uid> | Past runs (executionId, status, startedAt, durationMs, error) |
dcupl workflow trace --id <uid> --run <executionId> | --last | Node-by-node state for a run |
dcupl workflow run <key> --runner <uid> [--body <json> | --input <path>] | Trigger an already-deployed workflow without redeploying (--node for one node) |
# Find the run
dcupl workflow history --id <uid>
# => executionId status startedAt durationMs error
# Inspect node-by-node state
dcupl workflow trace --id <uid> --run <executionId>
# or trace the most recent run
dcupl workflow trace --id <uid> --lastworkflow template is useful for catching drift — if the template on the runner no longer matches your local file, redeploy.