Skip to content

Workflows

A workflow is a trigger plus a sequence of actions. You compose them on the visual canvas or via the assistant; the runtime executes them and keeps run history for inspection.

Workflows can start from:

  • HTTP / HTTPS — call the workflow as a webhook.
  • Schedule / Recurrence — every minute, hour, day, or cron expression.
  • Queue / topic — Service Bus, Event Hubs, Storage queue.
  • Connector events — many managed connectors expose triggers (e.g., new email, new file).
  • Another workflow — invoke this workflow from a parent.

Actions fall into a handful of categories:

CategoryExamples
HTTPGeneric REST calls — GET, POST, etc.
Built-inCompose, Parse JSON, Variables, Inline JavaScript.
ConnectorsBuilt-in (Service Bus, Storage, …) and managed (Outlook, Teams, SharePoint, …).
Control flowif, switch, for-each, do-until, parallel branches.
AgentsAI-driven actions with a system prompt and a toolset. See Agents.

Every action’s parameters accept either a literal value or a dynamic value computed from earlier steps. Click into any field and the Dynamic content / Expressions panel opens on the left, with two modes:

  • Dynamic content — drag any output from the trigger or an earlier action into the field. Outputs appear as named tokens (triggerBody().num1, outputs('Get_Current_Time')).
  • Expressions — write a function call using the platform’s expression language: @add(triggerBody()?.num1, 5), @formatDateTime(utcNow(), 'yyyy-MM-dd'), @if(empty(variables('orders')), 'none', 'present').

Dynamic content + Expressions panel

The same expression syntax works wherever a value is accepted — node parameters, conditional branches, loops, agent system prompts. The panel includes a live preview so you can validate the result before saving.

For logic that’s hard to express as a function call — string parsing, complex data shaping, multi-step calculation — drop in a built-in Inline JavaScript Code action. It runs in a sandboxed Node.js runtime, takes JSON inputs from the workflow, and returns a value the rest of the workflow can read.

// Action: Inline JavaScript Code
const orders = workflowContext.actions.Fetch_Orders.outputs.body;
return orders
.filter(o => o.total > 100)
.map(o => ({ id: o.id, customer: o.customerName, total: o.total }));

Use it sparingly — most transformations are clearer as a chain of built-in actions, and the JS sandbox can’t make network calls. For network-bound logic, use the HTTP action instead.

The code view (toggle on the bottom toolbar) opens the workflow’s JSON side-by-side with the canvas. Both views stay in sync — edit either, the other updates.

Code view side-by-side with the canvas

Inside the editor:

  • Auto-completion — start typing and the editor suggests matching action types, expression functions, and known properties of the schema. Press Ctrl + Space (or ⌃ Space) to force the popover.
  • Signature help — typing a function call shows the function’s signature and parameter docs inline.
  • Hover docs — hover any property to see its type and description.
  • Schema-aware diagnostics — invalid action types, malformed expressions, and missing required fields are underlined with a tooltip explaining the problem.

The same editor backs every place a code surface appears — the workflow code view, inline JavaScript actions, and the expression input — so the same auto-completion and validation are available everywhere.

  • Stateful workflows persist their full run history and support replay, retry, and long-running operations.
  • Stateless workflows run in-memory only and are optimised for short, fast executions.

Pick the mode when you create the workflow. You can change it later in workflow.json ("kind": "Stateful" / "Stateless").

Every workflow has two versions: a draft (what you’re editing) and the published version (what real traffic hits).

DraftPublished
What it isYour current in-progress editThe live version triggers actually fire against
Where edits goAuto-saved here while you workUpdated only when you click Publish
IndicatorDraft pill on the canvas toolbarPublished pill on the canvas toolbar
Run history bucketShown under “Drafts” in the Monitoring viewShown as “Production” runs

Designer toolbar showing the Published pill

Publishing copies the draft on top of the published version. There’s no separate “deploy” step — the next trigger fires the new version.

Not every trigger respects drafts. The pattern is: anything manually invokable works against drafts; anything time- or event-driven only fires against the published workflow.

Trigger kindFires from a draft?How to test
HTTP / Request, manualClick Test your draft in the designer (or the Run workflow button in the Monitoring tab) and provide a payload.
Schedule / Recurrence❌ — published onlyPublish first; then wait for the scheduled time (or shorten the schedule temporarily).
Event-driven (Service Bus, Event Hubs, Storage queue)❌ — published onlyPublish first; then push an event to the source.
Connector polling triggers (SaaS new-item-detected, etc.)❌ — published onlyPublish first; then trigger the event in the source SaaS app.

For a full end-to-end test of a non-HTTP trigger, the workflow has to be published. Iterate quickly on HTTP-triggered workflows with Test your draft, then publish once everything looks right.

The fastest way to experiment is right in the portal. Workflows you save publish to a draft you can run on-demand before you publish over the live version. See the Quickstart to walk through building your first one.