Most teams adopt Azure Logic Apps for the reason it markets itself: a workflow runs without anyone writing a server, a polling loop, or a connector library by hand. The first integration ships in an afternoon, the demo lands, and the platform feels solved. The trouble arrives three months later, when a workflow that was cheap at a hundred runs a day costs real money at a hundred thousand, when a trigger that fired reliably in testing silently skips a window in production, or when a connector that authorized once starts returning unauthorized and nobody can say why. The gap between using Logic Apps and understanding it is exactly this: the visual designer hides a precise execution engine, a billing model that punishes certain workflow shapes, and a hosting choice that should have been made before the first action was dragged onto the canvas. This deep dive closes that gap so you build flows that survive scale rather than ones that look finished in a screenshot.

The reader who finishes this article should leave holding a working mental model of Logic Apps as a workflow engine driven by triggers, actions, and connectors, able to choose between the Consumption and Standard plans deliberately, and able to reason about stateful versus stateless runs instead of accepting whatever the default offered. That is a sharper outcome than the documentation gives, because the documentation describes each feature in isolation while the failures engineers actually hit come from how the features interact: a billing model meeting a chatty workflow, a stateless run meeting a debugging session that needs history, a managed connector meeting a token that quietly expired over a weekend.
What Azure Logic Apps actually is and the model to hold
Azure Logic Apps is a managed workflow engine. You describe a sequence of steps, the platform runs them when something tells it to, and it handles the retries, the state between steps, the scaling, and the connection plumbing that you would otherwise write and maintain yourself. The unit you build is a workflow: a single trigger followed by one or more actions, arranged with conditions, loops, and branches as needed. The trigger decides when the workflow runs and what data starts it. The actions are the work the workflow performs once it starts. Everything else in the product, the connectors, the plans, the state options, exists to serve that trigger-and-actions core.
The mental model worth holding from the first day is that a Logic App is not a program you run, it is a definition the engine interprets. You author a workflow definition, expressed underneath the designer as JSON in a dialect called the Workflow Definition Language, and the runtime reads that definition each time the trigger fires. This matters because it explains behavior that surprises people who treat the designer as a code editor. The engine evaluates expressions at run time against the data flowing through the workflow, so a reference to an earlier action’s output is resolved when the run reaches that point, not when you save the design. It explains why a workflow can be edited while runs are in flight, and why the run history shows you the exact inputs and outputs of every action: the engine recorded each step’s evaluation as it interpreted the definition.
What does Azure Logic Apps automate, in one sentence?
Logic Apps automates integration and orchestration work: moving data between systems, reacting to events, calling APIs in sequence, and coordinating multi-step processes across services that were never designed to talk to each other. It is the glue layer, the place where a file landing in storage triggers a record in a database which triggers a notification, all without bespoke server code.
The product fits a recognizable shape of problem. You have several systems, a SaaS application, a database, a queue, an email service, an on-premises line-of-business app, and you need them to act in concert. A purchase order arrives, it must be validated, written to a system of record, acknowledged to the sender, and escalated if a field is missing. Writing that as a long-lived service means owning the hosting, the retries, the connection credentials to each system, the partial-failure handling, and the observability. Logic Apps absorbs that operational burden into the platform and leaves you describing the sequence. The trade is the one every managed platform makes: you give up some control over execution in exchange for not operating the machinery, and the rest of this article is largely about where that trade is favorable and where it quietly costs you.
How Logic Apps works internally at the level you need
Underneath the canvas sits a runtime that does four jobs on every run. It evaluates the trigger to decide whether a run should start and with what payload. It walks the action graph in dependency order, running actions as their inputs become available. It evaluates expressions and resolves references to earlier outputs as it goes. And, depending on the plan and the workflow type, it persists the inputs and outputs of each step so the run can be inspected, resumed, or resubmitted later. Understanding those four jobs is enough to debug almost anything Logic Apps does, because nearly every confusing behavior traces back to one of them.
Triggers come in distinct flavors, and the flavor governs how the engine decides to run. A recurrence trigger fires on a schedule the engine maintains. A request trigger exposes an HTTP endpoint and fires when something calls it. A polling trigger, the kind most managed connectors expose, has the engine check a source on an interval and start a run when it finds new data, tracking a cursor so it does not reprocess what it already saw. A webhook trigger registers a callback with an external system and waits to be notified rather than polling. The difference is not cosmetic. A polling trigger that checks every minute can miss nothing only if each check completes and advances its cursor; if a downstream system is slow and a check overlaps the next, or if the polling interval is longer than the rate at which items arrive and the batch size is capped, the cursor behavior is what determines whether you lose data or merely delay it.
How does a trigger actually start a workflow run?
A trigger evaluates on its schedule or on an inbound signal, and when its condition is met the engine creates a run, captures the trigger output as the run’s starting data, and begins executing actions. A polling trigger advances a stored cursor so the next evaluation only sees new items, which is why a paused workflow resumes without reprocessing old data.
Once a run starts, the engine executes the action graph. Each action declares, implicitly through its expressions, which earlier outputs it depends on. The engine runs an action as soon as its dependencies are satisfied, which means actions with no dependency on each other can run in parallel branches, and actions in sequence run strictly after their predecessor completes. This dependency-driven execution is why two parallel branches genuinely overlap in time and why a long chain of dependent actions runs only as fast as its slowest link. When an action calls an external service, the engine waits for the response, applies the action’s retry policy if the call fails in a retryable way, and records the result. The retry policy is a property of the action, not a global setting, so an action that hammers a fragile downstream system with aggressive retries is a local decision you can see and change.
State is the dimension that most changes behavior, and it is worth being precise. In the Consumption model and in stateful Standard workflows, the engine persists every action’s inputs and outputs to durable storage as the run proceeds. That persistence is what powers the run history view, the ability to resubmit a failed run, and the resilience that lets a run survive an infrastructure hiccup mid-flight. It is also work the engine performs on every step, which has a latency and a cost. Stateless Standard workflows skip most of that persistence: they hold state in memory for the duration of the run and discard it after, trading the run history and the mid-run durability for lower latency and higher throughput. The same workflow definition behaves differently depending on which mode it runs in, and choosing the wrong mode is a common and avoidable mistake covered in detail below.
The plans that shape every design decision
The single most consequential choice in Logic Apps happens before you place a single action: which hosting model the workflow runs on. There are two, and they are not interchangeable conveniences. They differ in where the workflow runs, how it is billed, what it can connect to, and what state options it offers. Picking the wrong one is the difference between a workflow that scales cheaply and one that generates a surprising invoice, and unwinding the choice later means rebuilding.
The Consumption model runs your workflow in a shared, multi-tenant environment that Microsoft operates. You author one workflow per Logic App resource, you do not manage any host, and you pay per action execution: roughly, every action the engine runs in every run is a metered event, with trigger evaluations and connector calls metered as well, subject to the published pricing that you should confirm against the current Azure pricing page rather than treating any figure here as fixed. The appeal is that idle workflows cost almost nothing and you operate no infrastructure. The hazard is the meter: a workflow with forty actions that runs a hundred thousand times is four million metered actions, and a design that loops over a large collection multiplies that further.
The Standard model runs your workflows on a single-tenant runtime hosted on an App Service plan or a comparable hosting plan that you provision. You can host many workflows in one Standard Logic App, the runtime is the same Azure Functions-based host under the covers, and you pay for the hosting plan, the compute you reserve, rather than per action. The appeal is predictable cost at volume and a richer feature set: virtual network integration, private endpoints, built-in operations that run in-process, and the stateful-versus-stateless choice. The hazard is that you now own a plan with a baseline cost whether it runs one workflow or fifty, so a single low-volume integration on Standard can cost more than the same integration on Consumption.
Which plan should I choose, Consumption or Standard?
Choose Consumption for low-to-moderate volume integrations where idle cost should be near zero and you want zero hosting to manage. Choose Standard when volume is high enough that per-action billing would exceed a plan’s fixed cost, when you need virtual network integration or private endpoints, or when you want several workflows sharing one host and the stateless option for latency.
This is where the namable rule of this article lives, the per-action-versus-hosting rule: Consumption bills every action so a chatty workflow gets expensive, while Standard bills the plan, so the cost model should pick the host before the workflow is built. The rule reframes the decision from a feature comparison into a single question about the workflow’s shape and frequency. A workflow that runs rarely and has few actions is cheap on Consumption and wasteful on Standard. A workflow that runs constantly, or that fans out over large collections, crosses a break-even point where the Standard plan’s fixed cost is less than the sum of metered actions, and past that point Consumption is the expensive choice. The break-even depends on action count, run frequency, and current pricing, so the discipline is to estimate metered actions per month and compare against a plan’s monthly cost before committing, not after the invoice arrives.
The plans also differ in connectivity, which sometimes decides the choice regardless of cost. Standard can integrate with a virtual network and reach private endpoints, so a workflow that must talk to a database or service that is not exposed publicly often has to be on Standard. Consumption reaches private resources through additional infrastructure rather than native integration. If the workload is network-bound to private resources, the plan question may already be answered before cost enters the discussion.
Stateful versus stateless workflows in Standard
Inside the Standard model sits a second choice that the Consumption model never exposes: whether a workflow runs stateful or stateless. The names are accurate but understate the consequence. A stateful workflow persists the inputs and outputs of every action to external storage as it runs, exactly as Consumption does, which gives you the full run history, the ability to resubmit, and durability across a host restart in the middle of a run. A stateless workflow keeps that data in memory only for the life of the run and writes nothing durable, so it finishes faster and handles far more concurrent runs on the same compute, at the price of no detailed run history and no mid-run resumption.
The trade-off has a clean decision boundary once you state it plainly. Stateful is for workflows where you need to audit what happened, debug by inspecting each step, resubmit a failed run without re-triggering the source, or guarantee that a half-finished run survives an infrastructure event. Stateless is for high-throughput, short-lived workflows where latency and concurrency matter more than forensics, where the work is idempotent enough that a failure can simply be retried from the start, and where the volume would make persisting every step’s data both slow and expensive. A request-response workflow fronting a synchronous API is a natural stateless candidate. A long order-fulfillment process that touches money is a natural stateful one.
What breaks when you pick the wrong state mode?
Picking stateless for a workflow you later need to debug leaves you with no run history to inspect, so a production failure becomes a guessing game. Picking stateful for a high-volume, latency-sensitive workflow adds storage writes to every step, raising latency and load until throughput suffers. The mode should match whether you value forensics or speed.
The common misdiagnosis here is treating run history as something you can add later. In a stateless workflow the data was never written, so when a run fails and you open the history expecting the inputs and outputs that would tell you what went wrong, there is nothing to see beyond the fact that the run failed. The fix is not a setting you toggle after the fact; it is a different workflow type, which means recreating the workflow as stateful. Teams that anticipate this build stateful from the start for anything they expect to operate and troubleshoot, and reserve stateless for the genuinely high-volume paths where they have accepted that a failure means a clean retry rather than an investigation. The richer event-driven designs that combine both, described in the patterns behind event-driven architecture on Azure, often route durable, auditable steps through stateful workflows and high-volume fan-out through stateless ones.
Triggers and actions: the execution model in depth
Every workflow has exactly one trigger and at least one action, and the relationship between them is the workflow’s contract with the outside world. The trigger is the only thing that can start a run, and it determines both the cadence of runs and the data each run begins with. Getting the trigger right is more than half of getting the workflow right, because a workflow that runs at the wrong time, runs too often, or starts without the data it needs is broken regardless of how well its actions are written.
Recurrence triggers are the simplest to reason about and the easiest to misuse. They fire on a fixed schedule the engine maintains, which is ideal for periodic work: a nightly export, an hourly reconciliation, a polling job that checks a source that has no event mechanism. The misuse is reaching for a tight recurrence as a substitute for an event. A recurrence trigger checking a queue every minute is a polling loop that runs whether or not there is work, metering trigger evaluations on Consumption and burning compute on Standard, when the same job driven by a real event mechanism would run only when there is something to do. When the source genuinely emits events, an event-driven trigger beats a recurrence one on both cost and latency.
Request triggers turn a workflow into an HTTP endpoint. The engine exposes a URL, and a call to that URL starts a run with the request body and headers as the trigger output. This is the foundation of synchronous integration: a caller invokes the workflow and waits for a response, which the workflow returns with a response action. The failure mode that searchers hit here is a malformed request producing a BadRequest, usually because the request did not match the schema the trigger expects or because authentication on the endpoint was not satisfied. The endpoint is public unless you secure it, so a request-triggered workflow needs either a shared access signature on the URL, an authorization policy, or network restrictions, and the absence of any of those is an exposure rather than a convenience.
Why does a trigger sometimes not fire when expected?
A trigger can appear not to fire for several distinct reasons: a polling trigger advanced its cursor past the item, the recurrence schedule does not align with when data arrives, a concurrency limit is holding runs in a queue, or the connector authorization expired and the trigger cannot poll. Each leaves a different fingerprint in the run and trigger history.
Polling connector triggers are where most of the subtlety lives. The engine checks the source on the configured interval, retrieves up to a batch limit of new items, and advances a cursor so it does not see them again. This is efficient and reliable when the arrival rate stays under the batch limit per interval. It becomes a data-loss-shaped problem when arrivals exceed what one poll can collect and the cursor advances anyway, or a latency problem when the interval is long relative to how quickly items must be processed. The diagnostic is the trigger history, which records each evaluation and whether it found data, separate from the run history that records what happened once a run started. Reading the trigger history is how you tell a trigger that never fired from a trigger that fired and produced a run that then failed, two problems with completely different fixes.
Actions are everything the workflow does after the trigger. They fall into categories that behave differently. A connector action calls an external system through a managed or built-in connector. A built-in action runs logic the runtime provides directly, such as parsing JSON, composing a value, or making a raw HTTP call. A control action shapes the flow without calling anything external: a condition branches, a switch routes, a loop iterates, a scope groups. The engine treats them uniformly in that each is a node in the dependency graph with inputs, outputs, and a retry policy, but they differ enormously in cost and behavior, which is why the next sections separate connectors from control logic.
Managed connectors versus built-in operations
Connectors are the feature that makes Logic Apps feel effortless and the feature that most quietly shapes cost and reliability. A connector is a pre-built integration with a system: a database, a SaaS application, a storage account, a messaging service. Instead of writing the client, handling the authentication, and parsing the responses, you configure the connector and call its operations as actions. The library is large and growing, which is the point, but connectors come in two kinds with different execution models, and the distinction is not cosmetic.
Managed connectors run outside your workflow’s host, in a shared connector infrastructure that Microsoft operates. When your workflow calls a managed connector action, the call leaves the workflow runtime, executes in that shared infrastructure against the target system, and returns. This is what lets a Consumption workflow with no host of its own reach hundreds of systems, and it is why managed connector actions are metered and why their latency includes a hop to the connector service. Built-in operations, available in the Standard model, run in-process inside the workflow’s own runtime. A built-in connector for a service executes within your host rather than calling out to shared infrastructure, which lowers latency, avoids the per-call metering of the managed path, and can participate in virtual network integration because it runs where your host runs.
How do managed and built-in connectors differ in practice?
A managed connector runs in shared Microsoft-operated infrastructure, so it works from any plan but adds a network hop and per-call metering. A built-in connector runs in-process in the Standard runtime, so it is lower latency, avoids the managed-call meter, and can reach private networks, but built-in coverage is narrower than the full managed library.
The practical consequence is a design lever in the Standard model: where a built-in operation exists for the system you need, preferring it over the managed equivalent reduces latency and cost. Where only a managed connector exists, you accept the hop and the metering as the price of reach. On Consumption, every connector call is managed, so the design lever is to minimize the number of connector calls a workflow makes rather than to choose between connector types. This connects directly to the billing model: on Consumption a workflow’s cost is dominated by how many connector actions and how many total actions it executes per run multiplied by run frequency, so collapsing three connector calls into one, or moving conditional logic before an expensive call so it only runs when needed, is real money saved.
Connectors also introduce the dependency that fails most often in production, which is authorization, and that deserves its own treatment.
Connection authorization and token refresh
A connector needs credentials to reach its target system, and those credentials live in a connection resource that the workflow references. The connection holds the authorization: an OAuth grant to a SaaS application, a key to a storage account, a managed identity assignment, a service principal. The workflow does not store the secret; it points at the connection, and the connection holds or brokers the credential. This indirection is good design, it keeps secrets out of the workflow definition, but it creates the failure that surprises teams more than any other in Logic Apps: the connection’s authorization can expire.
OAuth-based connections to SaaS systems are the usual culprit. When you authorize such a connection interactively, the connector obtains a token and a refresh token, and it refreshes the access token as it expires. That refresh works until something invalidates it: the refresh token itself expires after the identity provider’s configured lifetime, the granting user’s password changes, the consent is revoked, conditional access policy changes, or the account is disabled. When any of those happens, the connector can no longer obtain a valid token, and every action through that connection starts returning an unauthorized error. The workflow did not change. The credential behind it did, silently, often over a weekend, and the first symptom is a wave of failed runs on Monday.
Why does a connector suddenly return unauthorized?
A connector returns unauthorized when the connection’s stored credential can no longer produce a valid token: the refresh token expired, the user who authorized it changed their password or was disabled, consent was revoked, or a conditional access policy now blocks the grant. The workflow is unchanged; the identity behind the connection is what broke.
The durable fix is to avoid user-delegated OAuth for connections that must run unattended for years. Where the connector supports it, authorize connections with a managed identity, which the platform manages and which does not carry a human user’s password lifecycle or interactive consent. A managed identity assigned to the Logic App, granted the specific role it needs on the target resource, removes the expiring-refresh-token failure entirely for the systems that support it. Securing connections this way is the same discipline that governs other Azure services, and the role-assignment thinking carries over directly from how managed identities authorize against any resource. For connections that genuinely require a user grant, the operational answer is monitoring: alert on the unauthorized error pattern so the re-authorization happens before the backlog grows, rather than discovering it from an angry downstream team.
Control actions and concurrency
Control actions are how a workflow makes decisions and repeats work, and they are where workflow logic either stays readable or collapses into something nobody can maintain. The condition action branches on a boolean, running one path when true and another when false. The switch action routes on a value to one of several cases. The scope groups a set of actions so they can be treated as a unit, which matters for error handling because a scope can be configured to run only after another scope succeeds, fails, is skipped, or times out. Loops come in two forms: a for-each iterates over a collection, and an until loops while a condition holds. These are the structured-programming primitives, expressed as workflow nodes, and they compose the same way control flow composes in code.
The for-each loop is where concurrency becomes a design decision rather than a default. By default a for-each can run its iterations in parallel up to a degree of concurrency, which is fast but means the iterations do not run in order and may overwhelm a downstream system that cannot absorb the parallel load. You can cap the degree of concurrency, down to one for strictly sequential processing, and the right setting depends on whether order matters and what the downstream system can tolerate. A for-each writing to a system that requires ordered, one-at-a-time inserts must run sequentially; a for-each calling an idempotent, high-capacity API can run wide. The misconfiguration is leaving the default parallelism on a loop that calls a fragile downstream service, which produces intermittent throttling and failures that look random until you connect them to the loop’s concurrency.
How do I stop a loop from overwhelming a downstream system?
Set the for-each concurrency control to a degree the downstream system can absorb, or to one for strictly sequential processing. The default runs iterations in parallel, which is fast but can flood a rate-limited or order-sensitive target. Capping concurrency trades throughput for stability, which is the right trade when the target is the bottleneck.
Workflow-level concurrency is a separate and equally important control. A trigger can be configured to limit how many runs of the workflow execute at once. With concurrency unbounded, a burst of triggering events starts a burst of simultaneous runs, which can overwhelm shared downstream resources or hit the platform’s own limits. With concurrency capped, excess runs queue and execute as capacity frees up, smoothing the load. The symptom of an unset or wrong concurrency limit is runs stuck in a queued state, which engineers sometimes misread as the platform being slow when it is actually the concurrency control doing its job, or the absence of that control letting a stampede form. The messaging-heavy designs that drive many Logic Apps, the kind built on Azure Service Bus queues and topics, often pair the queue’s own delivery controls with the workflow’s concurrency cap so that neither the broker nor the workflow becomes the point that floods.
Error handling in Logic Apps is built from scopes and the run-after configuration rather than a try-catch keyword. You place actions in a scope, then add a second scope configured to run only if the first failed, which becomes your catch block. Inside the catch scope you can read the failure, log it, notify, or compensate. This is more explicit than exception handling in code, which is both its strength, the failure paths are visible on the canvas, and its weakness, you must build them deliberately rather than relying on a language construct. A workflow with no error-handling scope simply fails at the first unrecoverable action and stops, which is acceptable for a stateful workflow you will resubmit and dangerous for a stateless one where the run leaves no trace.
The limits and quotas that shape design
Logic Apps enforces limits that, like every Azure service, are revised over time and must be confirmed against the current official documentation rather than memorized, but the categories of limit are stable enough to design against. There is a limit on how long a single run may last, which means a workflow that waits on a long-running external process should not block synchronously for hours but should use a pattern that releases and resumes. There are limits on the size of the message a workflow can handle in memory, which means very large payloads should be handled by reference, pointing at a blob rather than carrying the bytes through the workflow. There are limits on how many iterations a loop may perform and how large a collection a for-each may process, which means processing an unbounded collection requires pagination or chunking rather than one enormous loop.
What is the maximum run duration for a Logic App?
A single Logic App run has a maximum duration enforced by the platform, after which the run is terminated, and the exact value depends on the plan and current limits, so confirm it against the official Azure limits documentation. The design implication is constant: a workflow that must wait on a slow external process should use an asynchronous pattern that releases and resumes rather than blocking for the whole wait.
The duration limit is the one that most often forces a redesign. A workflow that calls an external system which itself takes a long time to complete should not hold a synchronous action open for that entire wait. The pattern that survives the limit is asynchronous: the workflow kicks off the long operation, the workflow either ends and a separate trigger resumes the process when the operation finishes, or the workflow uses a polling pattern with a webhook callback so it is not consuming a run’s duration budget while it waits. This is the same asynchronous-messaging discipline that decouples any two systems with different speeds, and the workflow that respects it stays inside the platform’s limits while a naive synchronous version eventually hits the wall when an external call runs long.
The failure modes and how to avoid them
Most production trouble with Logic Apps clusters into a handful of recurring failure modes, and each has a fingerprint that tells you which one you are looking at. Learning the fingerprints turns a vague “the workflow is broken” into a specific diagnosis with a known fix, which is the difference between an hour of guessing and a five-minute correction.
The chatty-workflow-on-Consumption failure is a billing failure rather than a functional one, and it is the most common expensive mistake. The workflow runs correctly, the outputs are right, and the invoice climbs because the design multiplied actions: a workflow with many actions, run frequently, looping over collections, each iteration metered. The fingerprint is a cost report dominated by action executions on a single workflow. The fix is partly redesign, collapsing actions and gating expensive calls behind conditions, and partly the plan decision, moving a high-volume workflow to Standard where the host’s fixed cost beats the per-action meter. This is the per-action-versus-hosting rule in its diagnostic form: when the meter dominates the bill, the host was the wrong choice for the volume.
The expired-connection failure presents as a sudden wave of unauthorized errors across every run that uses one connection, with no change to the workflow. The fingerprint is uniformity: not one action failing intermittently but every run through that connection failing the same way starting at a specific time. The fix is re-authorization, and the prevention is a managed identity where supported and alerting on the pattern where not. Because the failure is silent until a run needs the connection, the workflows that catch it earliest are the ones with a monitor watching for the unauthorized signal rather than the ones waiting for a human to notice the backlog.
The downstream-throttling failure shows up as intermittent failures, often with a 429 or a timeout, that correlate with load rather than with any particular input. The fingerprint is that the same action succeeds when traffic is light and fails when a burst arrives, frequently inside a parallel for-each. The fix is concurrency control on the loop or the trigger to keep the workflow inside what the downstream system can absorb, combined with sensible retry policies so a transient throttle is retried rather than treated as a hard failure. The retry policy is per action, so an action calling a rate-limited service can carry a backoff retry that smooths over brief throttling without manual intervention.
The trigger-not-firing failure splits into the sub-cases covered earlier, and the discipline is to read the trigger history before the run history. A trigger that never produced a run leaves its evidence in the trigger history: it evaluated and found nothing, or it could not evaluate because its connection was unauthorized, or its concurrency cap held runs in a queue. A trigger that produced a run which then failed leaves its evidence in the run history. Confusing the two sends engineers debugging the actions when the problem was the trigger, or tuning the trigger when the actions were at fault. The two histories are separate views for exactly this reason.
The lost-state-on-stateless failure is the one that only appears when something has already gone wrong. A stateless workflow fails, an engineer opens the run history to investigate, and there is nothing to investigate because stateless runs do not persist step data. The fingerprint is the absence of detail itself. There is no fix after the fact for that specific run; the prevention is choosing stateful for any workflow you expect to operate and troubleshoot, and reserving stateless for paths where a failure means a clean retry rather than an investigation.
The Logic Apps plan and state decision table
The findable artifact of this article is a single table that turns the plan and state decision into a lookup against the shape of your workload. Match your workload profile to the row, and the columns give the plan, the state mode, and the one factor that decided it. This is the InsightCrunch Logic Apps plan and state table, and it is meant to be the thing you check before you build, not after the bill.
| Workload profile | Plan | State mode | Deciding factor |
|---|---|---|---|
| Low-volume integration, runs occasionally, few actions | Consumption | N/A (Consumption persists by default) | Idle cost near zero beats a plan’s fixed cost at low frequency |
| High-volume integration, runs constantly or fans out over collections | Standard | Stateful | Per-action metering would exceed the plan’s fixed cost past the break-even |
| Latency-sensitive, high-throughput, idempotent, retry-on-failure acceptable | Standard | Stateless | Throughput and low latency matter more than run history; failure means clean retry |
| Must reach private resources behind a virtual network or private endpoint | Standard | Stateful or stateless by need | Native virtual network integration is a Standard capability |
| Auditable, must resubmit failed runs, touches money or records of record | Consumption or Standard | Stateful | Forensic run history and resubmission require persisted state |
| Several related workflows that should share a host and scale together | Standard | Mixed by workflow | One plan hosts many workflows; cost is amortized across them |
The table encodes the per-action-versus-hosting rule across the cases engineers actually meet. The first two rows are the pure cost decision: low frequency favors Consumption, high frequency or fan-out favors Standard. The third row is the state decision inside Standard: when speed beats forensics and retries are safe, stateless wins. The fourth row is the connectivity override: a private-network requirement points at Standard regardless of cost. The fifth row is the auditability requirement: anything you must resubmit or trace needs persisted state. The sixth row is the consolidation case: many workflows sharing one Standard host amortize the fixed cost that would have been wasteful for a single low-volume flow.
How Logic Apps is billed and how to control the cost
Billing follows the plan, and understanding it precisely is what lets you predict cost rather than discover it. On Consumption, the meter counts executions: trigger evaluations, built-in actions, and connector calls each register, with the connector calls and standard actions metered at the published rates that you must verify against the current Azure pricing because they are revised over time. The mental arithmetic that prevents surprises is straightforward: estimate the number of metered events per run, multiply by runs per month, and compare against alternatives before committing. A workflow with thirty actions running ten thousand times a month is three hundred thousand metered actions, and whether that is cheap depends entirely on the current rate and on whether a Standard plan’s monthly cost would have been lower.
On Standard, the meter is the hosting plan. You pay for the compute the plan reserves, scaled by the plan tier and the instances it runs, whether the workflows are busy or idle. The cost is predictable and decoupled from action count, which is exactly why high-volume workflows belong here: a plan that costs a fixed amount per month can run millions of actions without the cost moving, where the same actions on Consumption would meter every one. The hazard inverts the Consumption hazard: a Standard plan running one occasional workflow pays the full plan cost for near-zero work, so consolidation matters, putting several workflows on one plan so the fixed cost is justified.
How do I reduce the cost of a Logic App?
On Consumption, cut the number of metered actions: collapse steps, gate expensive connector calls behind conditions so they only run when needed, and move high-volume workflows to Standard once the per-action total exceeds a plan’s fixed cost. On Standard, consolidate workflows onto one plan and right-size the plan so you are not paying for idle capacity.
The cost levers therefore depend on the plan. On Consumption you optimize by reducing metered events: fewer actions per run, conditional gating so expensive calls are skipped when not needed, and avoiding loops that multiply actions across large collections. On Standard you optimize by right-sizing the plan and consolidating workflows so the fixed cost serves real volume. The cross-plan lever is the migration itself: a workflow that grows from low to high volume should be moved from Consumption to Standard at the point where its metered cost crosses the plan cost, and recognizing that crossing early avoids paying the Consumption premium on a workflow that has outgrown it. The cost reasoning here mirrors the broader serverless billing trade-offs, and the same per-execution-versus-reserved-capacity thinking that governs how Azure Functions serverless billing works applies to choosing between Logic Apps plans.
Monitoring, run history, and observability
A workflow you cannot see is a workflow you cannot operate, and Logic Apps gives you observability that depends, again, on the state mode. Stateful runs record the inputs and outputs of every action, so the run history is a complete forensic record: you open a failed run, walk to the action that failed, and read exactly what it received and what it returned. This is the single most useful debugging tool the platform offers, and it is why stateful is the right default for anything you operate. The trigger history sits alongside it, recording each trigger evaluation so you can distinguish a trigger that never fired from a run that fired and failed.
Beyond the built-in history, workflows emit telemetry that you can route to a centralized monitoring store for alerting and analysis, and connecting Logic Apps to a monitoring workspace is how you turn per-run history into fleet-wide visibility. The alerting that matters most is on the failure patterns described above: a spike in unauthorized errors that signals an expired connection, a rise in 429s that signals downstream throttling, a drop in runs that signals a trigger that stopped firing. Each of those patterns is detectable in telemetry before a human notices the downstream impact, and the workflows that stay healthy are the ones with alerts on the patterns rather than the ones waiting for a complaint.
How do I debug a failed Logic App run?
Open the run history for the failed run, which on a stateful workflow records the inputs and outputs of every action. Walk to the first failed action and read its inputs and error output, which usually names the cause directly. If no run appears at all, check the trigger history instead, because the failure was in the trigger, not the actions.
The observability gap to plan around is the stateless one. Because stateless workflows do not persist step data, their run history is thin, so operating a stateless workflow at scale leans harder on emitted telemetry and on designing the workflow to log what matters explicitly. A team running stateless paths for throughput should compensate by routing custom logging to a monitoring store so that, even without per-step run history, there is enough signal to detect and characterize failures. This is part of the cost of the stateless trade, and it is worth stating plainly so the choice is made with eyes open.
When to use Logic Apps and when to reach for an alternative
Logic Apps is the right tool when the work is integration and orchestration expressed as a workflow, especially when it leans on the connector library to reach systems you would otherwise write clients for. A process that coordinates several SaaS systems, a data movement that hops between a queue, a database, and a notification, an approval flow with branches and waits, a scheduled job that reconciles two systems: these are squarely Logic Apps work, where the visual workflow, the connectors, and the managed retries and state earn their keep. The more of the work is pre-built connector calls arranged in a sequence, the more decisively Logic Apps wins, because that is exactly the work it removes from you.
Logic Apps is the wrong tool when the work is dominated by custom computation rather than orchestration. A workflow that needs heavy data transformation, complex algorithms, tight loops over large datasets, or logic that is genuinely code rather than a sequence of calls is fighting the platform: every step is an action, every action is metered or hosted, and expressing real computation as workflow actions is verbose, slow, and expensive compared to writing it as code. That is the boundary where you reach for a code-first compute service. The decision between a workflow and code is the subject of its own analysis, and the trade-offs between Azure Functions and Logic Apps come down to whether the work is mostly custom logic, which favors code, or mostly connector-driven orchestration, which favors the workflow.
When should I use Logic Apps instead of writing code?
Use Logic Apps when the work is orchestration and integration, sequencing calls across systems with the connector library doing the heavy lifting, and when a visual, managed workflow with built-in retries and state is worth more than fine-grained control. Reach for code when the work is custom computation, heavy transformation, or logic that is awkward and expensive to express as a sequence of metered actions.
The two often combine rather than compete. A common and effective pattern uses Logic Apps for the orchestration, the triggering, the connector-driven steps, the branching and the waits, and calls out to a code-first function for the one step that needs real computation. The workflow stays readable and the computation stays where it belongs, and neither tool is bent into a job it does poorly. Recognizing that you can compose them, rather than choosing one for everything, is what lets a system use the right tool for each part of the work.
The single best way to think about Logic Apps
If you hold one idea about Logic Apps, hold this: it is a workflow engine where a trigger decides when, actions decide what, connectors decide how it reaches the outside world, the plan decides how it is billed and what it can connect to, and the state mode decides whether you can see what happened. Every design question reduces to those five dimensions, and every production failure traces back to one of them being set wrong. A workflow that costs too much has the wrong plan for its volume. A workflow you cannot debug has the wrong state mode. A workflow that floods a downstream system has the wrong concurrency. A workflow that fails authorization has a connection whose credential expired. A workflow that runs at the wrong time has the wrong trigger. The platform is not mysterious once you map a symptom to its dimension.
The discipline that follows from the model is to make the structural choices first and the workflow logic second. Decide the plan from the volume and the connectivity needs. Decide the state mode from whether you value forensics or speed. Decide the trigger from the real cadence of the work. Set concurrency from what the downstream systems can absorb. Choose managed identity for connections wherever the connector supports it. Only then arrange the actions. Teams that build in that order ship workflows that survive scale; teams that drag actions onto the canvas first and discover the structural constraints later are the ones rebuilding under pressure when the volume arrives or the bill lands. You can practice exactly this order of operations by building a workflow, wiring a connector, and comparing a stateful and a stateless run when you run the hands-on Azure labs and command library on VaultBook, which is where the abstractions in this article turn into a flow you can watch execute.
The strategic verdict
Azure Logic Apps earns its place as the integration and orchestration layer of an Azure system, and it earns it most when you respect the two decisions that the visual designer hides: the plan and the state mode. The per-action-versus-hosting rule is the compass: Consumption is the right home for low-volume, occasional, connector-driven workflows where idle cost should be nothing and you operate no host, and Standard is the right home for high-volume, network-bound, or consolidated workflows where a fixed plan cost beats the per-action meter and the stateless option buys throughput. Get that decision right before the first action, and Logic Apps is a platform that removes an enormous amount of integration toil. Get it wrong, and you discover the cost or the missing run history at the worst possible time, on an invoice or in an incident.
The mature posture toward Logic Apps treats it as one tool in a composition rather than a universal hammer. It orchestrates, it integrates, it waits and branches and retries, and it hands the genuinely computational steps to code. It connects systems through a connector library that is its greatest strength and its most common point of failure through expiring authorization, which managed identity and monitoring address. It scales cheaply when the plan matches the volume and expensively when it does not. Build with the model in hand, make the structural choices deliberately, and Logic Apps becomes the dependable connective tissue of a system rather than a source of surprises.
The Workflow Definition Language and how expressions resolve
Beneath the visual designer, a workflow is a JSON document written in the Workflow Definition Language, and understanding that document removes a whole class of confusion. The designer is a view over the definition, not the definition itself, which is why an advanced workflow is sometimes edited more precisely in the code view than by dragging boxes. The definition names each action, declares its type and inputs, and expresses the data flowing between actions through expressions. When an action’s input references the output of an earlier action, that reference is an expression the engine resolves at run time, when execution reaches the action, against the data the run has accumulated so far.
This run-time resolution is the source of behavior that puzzles people who treat the designer as a static form. An expression that reads a property off an earlier action’s output succeeds only if that property exists at the moment the expression evaluates, so an action that runs before its data is available, or that references a property an upstream action did not actually produce, fails at run time rather than at save time. The engine cannot validate that the data will be shaped correctly when you save the design, because the shape depends on what the external systems return during the run. The run history then shows you the resolved values, the actual inputs the expression produced and the actual output the action returned, which is exactly the information you need to see why an expression evaluated to something unexpected.
Why does an expression fail at run time but look fine in the designer?
An expression resolves against live run data, not against the static design, so a reference to a property that an upstream action did not actually produce, or that is null for a particular input, fails only when the run reaches it. The designer cannot validate the shape of data external systems will return, so correctness shows up at run time in the history.
Expressions also handle the small transformations a workflow needs without a separate compute step: concatenating strings, formatting dates, reading a value from a JSON payload, applying a default when a property is missing. Keeping those transformations in expressions where they are simple, and pushing genuinely complex transformation out to code, is the balance that keeps a workflow both readable and economical. A workflow stuffed with deeply nested expressions doing real computation is a sign the work has outgrown what expressions should carry, and that the computational step belongs in a function the workflow calls rather than in the workflow itself.
Deploying Logic Apps as code
A workflow that exists only as something clicked together in the portal is a workflow you cannot reliably reproduce, promote across environments, or recover after a mistake, so treating Logic Apps as infrastructure to be defined in code is the discipline that separates a durable system from a fragile one. Because a workflow is fundamentally a definition document, it lends itself to being captured as a template and deployed through a repeatable pipeline, the same way any other Azure resource is. The workflow definition, the connections it references, and the plan it runs on can all be expressed declaratively and deployed together, so that a new environment is stood up by running the deployment rather than by re-clicking the workflow.
The wrinkle that catches teams is the connection authorization, which does not deploy cleanly as a secret in a template. A connection’s credential, especially an interactive OAuth grant, is not something you want baked into a template, and often it must be authorized in the target environment after the resources deploy. The pattern that works is to deploy the workflow and the connection resources declaratively, parameterize the connection so it points at the right target per environment, and handle the authorization step deliberately, preferring managed identity where the connector supports it precisely because a managed identity deploys and authorizes without a human-held secret. Parameterizing the workflow, the endpoints it calls, the connection targets, the schedule, the concurrency, so that the same definition deploys to development, test, and production with environment-specific values, is what makes the workflow portable rather than hardcoded to one environment.
How do I promote a Logic App across environments?
Capture the workflow definition, its connections, and its plan as a parameterized template, then deploy that template to each environment with environment-specific values for endpoints, connection targets, and settings. Handle connection authorization in the target environment after deployment, favoring managed identity so no human-held secret travels in the template, which keeps promotion repeatable and secure.
Defining the workflow as code also gives you the version control and review that clicking in the portal cannot. The definition lives in source control, changes go through review, and a deployment can be rolled back to a previous definition if a change misbehaves. This is the same infrastructure-as-code rigor that governs the rest of an Azure estate, and applying it to Logic Apps means a workflow change is a reviewed, traceable, reversible event rather than an untracked edit someone made in the portal at two in the morning that nobody can reconstruct.
Securing a Logic App
Security for a Logic App spans three surfaces: how the workflow is triggered, how it authenticates to the systems it calls, and how its own definition and secrets are protected. Each surface has a default that is convenient and an exposure that follows if you leave the default in place. The request-triggered workflow is the clearest example. Its endpoint is reachable by anyone who has the URL unless you secure it, so a workflow that does real work behind a request trigger needs a shared access signature on the URL, an authorization policy that validates the caller, or network restrictions that limit who can reach it. Treating the obscurity of the URL as security is the exposure; an endpoint that mutates data or moves money must validate its caller.
Authentication to downstream systems is the connection surface, and the recurring guidance applies: prefer managed identity over user-delegated or secret-based authorization wherever the connector supports it. A managed identity assigned to the Logic App, granted the least privilege it needs on each target resource, removes both the expiring-credential failure and the risk of a long-lived secret leaking. The principle of least privilege is concrete here: the identity should hold exactly the role the workflow’s actions require on each resource and nothing more, so that a compromise of the workflow cannot reach beyond what the workflow legitimately touches. Over-permissioning a Logic App’s identity, granting broad access because it is easier than scoping the exact role, is the misconfiguration that turns a workflow compromise into a broader breach.
How should a Logic App authenticate to other Azure services?
Wherever the connector supports it, authenticate with a managed identity assigned to the Logic App and granted the least-privilege role it needs on each target resource. This removes the expiring-credential failure of user OAuth and avoids storing long-lived secrets. Scope the identity to exactly the roles the workflow’s actions require, so a compromise cannot reach beyond what the workflow legitimately uses.
The definition and its secrets are the third surface. Parameters that carry sensitive values should be sourced from a secret store rather than embedded in the workflow definition, so the definition can live in source control without leaking credentials, and the secrets are rotated in the store without editing the workflow. Combined with the request-endpoint protection and the managed-identity authentication, this gives a Logic App a coherent security posture: callers are validated, downstream access is least-privilege and credential-managed, and secrets never live in the definition. A workflow built this way is auditable and defensible; a workflow with an open request endpoint, an over-permissioned identity, and a secret in a parameter is an incident waiting for a trigger.
Migrating a workflow from Consumption to Standard
The most common lifecycle event for a successful Logic App is outgrowing the plan it started on. A workflow built on Consumption because it was low-volume and cheap to start becomes high-volume as the system it serves grows, and at some point the per-action meter crosses the fixed cost of a Standard plan. Recognizing that crossing and migrating deliberately is what keeps a maturing workflow economical, and doing it before the invoice forces the issue is the difference between a planned migration and a panicked one.
The migration is a rebuild rather than a flip of a switch, because Consumption and Standard are genuinely different hosting models with different runtimes underneath. The workflow definition is largely portable, the trigger-and-actions logic carries over, but the connection model, the way built-in versus managed operations are chosen, and the state and networking options differ enough that the move is recreating the workflow on Standard rather than migrating it in place. The payoff is access to the Standard capabilities the workflow now needs, predictable cost at the new volume, in-process built-in connectors that lower latency and cost, the stateful-versus-stateless choice, and native virtual network integration, plus the consolidation benefit of placing the migrated workflow on a plan it can share with related workflows.
When should I migrate a Logic App from Consumption to Standard?
Migrate when the workflow’s monthly metered action total crosses the monthly cost of a Standard plan, when it needs native virtual network integration or private endpoints, or when several related workflows would benefit from sharing one host. The first signal is usually a Consumption bill dominated by action executions on a workflow that has grown beyond the low-volume profile Consumption suits.
Planning the migration around the structural decisions makes it clean. You decide the state mode the workflow needs on Standard, choose built-in operations over managed connectors where they exist to capture the latency and cost benefit, set the networking integration if the workflow must reach private resources, and size the plan to the combined volume of every workflow you intend to host on it. Then you rebuild the workflow definition on the new host, re-establish the connections with managed identity where possible, validate against the run history that it behaves identically, and cut over. Treating it as a deliberate rebuild against the model in this article, rather than an attempt to copy a workflow wholesale, is what produces a Standard workflow that takes full advantage of the plan rather than one that merely runs there.
Handling large payloads and binary data
The message-size limit is the constraint that quietly reshapes any workflow moving substantial data, and designing around it from the start avoids a rebuild when the data grows. A Logic App carries the data flowing through it in memory between actions, and the platform caps how large a single message that data may be, a value you confirm against current documentation because it is revised over time. A workflow that copies a small JSON record between systems never approaches the cap; a workflow that pulls a large file, a multi-megabyte document, an image, a sizable export, and tries to carry the bytes through every action will hit it, and the failure arrives precisely when the data grows past the threshold rather than during the small-file testing that made the design look sound.
The pattern that survives is handling large data by reference rather than by value. Instead of pulling a large blob into the workflow and carrying it through actions, the workflow passes the location of the data, a blob path, a storage reference, and lets the systems that need the bytes fetch them directly. The workflow orchestrates the movement, who reads from where and writes to where, without ever holding the full payload itself, which keeps the message small regardless of how large the underlying data is. Where the data genuinely must pass through the workflow, chunking it into pieces under the limit and processing the pieces is the fallback, but by-reference handling is the cleaner design and the one to reach for first.
How do I handle large files in a Logic App?
Move large data by reference rather than carrying the bytes through the workflow. Pass the blob path or storage location between actions and let the systems that need the content read and write it directly, so the workflow orchestrates the movement without holding the full payload. This keeps each message under the platform’s size limit regardless of how large the underlying file grows.
The same reasoning applies to collections. A workflow that processes a small list in a for-each is fine, but a workflow that loads an unbounded collection into memory and iterates it will hit both the message-size limit and the loop-iteration limit as the collection grows. The durable design pages through the source, processing a bounded batch per run or per iteration, rather than assuming the whole collection fits. Pagination and chunking are the techniques that let a workflow process arbitrarily large inputs within fixed per-run limits, and a workflow that ignores them works in testing and fails the day the data outgrows the limit nobody designed against.
Reliability patterns that make a workflow resilient
A workflow that runs once in a demo and a workflow that runs reliably for years are different artifacts, and the difference is the reliability patterns built into the second. The first pattern is idempotency. Because triggers can fire more than once for the same logical event under some failure conditions, and because a resubmitted run replays the workflow, an action that is not safe to run twice can corrupt data when the workflow runs twice. Designing actions to be idempotent, writing with a key that makes a duplicate write a no-op, checking whether the work was already done before doing it, means a duplicate run is harmless rather than damaging. The workflows that survive operational reality assume at-least-once execution rather than exactly-once and build the steps to tolerate it.
The second pattern is deliberate handling of the messages and events a workflow consumes. When a workflow is driven by a queue or a topic, the broker’s own delivery semantics matter as much as the workflow’s logic: a message that the workflow fails to process should not vanish, and a message that repeatedly fails should not block the queue forever. Pairing the workflow with the broker’s dead-letter handling, so a message that cannot be processed after retries lands somewhere for inspection rather than being lost or looping, is what keeps a poison message from taking down the pipeline. This is the same dead-letter discipline that governs robust messaging generally, and the way a workflow consumes from a queue should respect the broker’s delivery guarantees rather than assume every message processes cleanly on the first try.
How do I make a Logic App workflow resilient to failures?
Build idempotent actions so a duplicate or resubmitted run is harmless, since execution is at-least-once rather than exactly-once. Pair queue-driven workflows with the broker’s dead-letter handling so a message that repeatedly fails is set aside rather than lost or looping. Add error-handling scopes to catch and compensate, and prefer stateful workflows so a failed run can be inspected and resubmitted.
The third pattern is the resubmission posture, which depends on the state mode chosen earlier. A stateful workflow that fails partway can be resubmitted from the run history, replaying with the original trigger data, which is invaluable when a transient downstream outage caused a batch of failures that simply need to be re-run once the downstream recovers. This is only possible because the run persisted its state, which is one more reason stateful is the right default for anything operational. A stateless workflow has no run to resubmit, so its reliability story is necessarily a clean retry from the source rather than a replay, and the source must be able to re-emit the event for that to work. Matching the reliability strategy to the state mode, replay for stateful, re-emit for stateless, is part of designing the workflow honestly rather than discovering the gap during an incident.
Common Logic Apps patterns engineers actually build
The abstractions become concrete in the patterns teams build repeatedly, and recognizing your problem in one of them shortens the path from blank canvas to working workflow. The integration-glue pattern is the most common: a trigger on one system, a sequence of connector actions that transform and route the data, and a write to one or more other systems, with a branch for the error case. A file landing in storage triggers parsing, validation, a database write, and an acknowledgment, with a failure path that quarantines a bad file and notifies an owner. This is Logic Apps at its most natural, connector-driven movement with branching, and it lives comfortably on Consumption when the volume is modest.
The approval-and-wait pattern uses the workflow’s ability to pause and resume around a human or external decision. A request arrives, the workflow records it, sends an approval request, and waits for the response before continuing, branching on approve or reject. Because waiting can run long, this pattern respects the run-duration limit by using a callback or resumable design rather than blocking synchronously for the entire wait, which is exactly the asynchronous discipline the limits section described. The fan-out-and-collect pattern processes a collection in parallel and then gathers the results, using a for-each with tuned concurrency so the parallelism matches what the downstream systems absorb, then aggregating the outcomes for a summary or a single downstream write.
What are the most common Logic Apps workflow patterns?
The recurring patterns are integration glue (trigger, transform, route, write, with an error branch), approval-and-wait (pause around a human or external decision using a resumable design), fan-out-and-collect (process a collection in parallel with tuned concurrency, then aggregate), and event reaction (a discrete event triggers a short reactive workflow). Each maps to a workload shape and a plan-and-state choice from the decision table.
The event-reaction pattern is the lightweight one: a discrete event, a record created, a message published, a resource changed, triggers a short workflow that reacts, often a few actions and a single downstream effect. When these events arrive at high volume, the pattern leans toward Standard with stateless workflows for throughput, and when they arrive occasionally it sits well on Consumption. The patterns are not exclusive, and a substantial system composes them, integration glue feeding an event-reaction path that occasionally invokes an approval-and-wait, but naming the pattern your problem matches tells you immediately which plan and state mode from the decision table apply, which is the whole point of having the model before the canvas. These same orchestration shapes recur across the broader event-driven designs the series covers, and a workflow is frequently one participant in a larger choreography of services reacting to one another.
Frequently Asked Questions
Q: What is Azure Logic Apps and what does it automate?
Azure Logic Apps is a managed workflow engine that automates integration and orchestration: moving data between systems, reacting to events, calling APIs in sequence, and coordinating multi-step processes across services that were not built to talk to each other. You describe a workflow as a trigger followed by actions, and the platform handles the scaling, retries, state, and connection credentials. It fits problems where several systems, a database, a SaaS app, a queue, an email service, must act in concert, and it removes the operational burden of hosting and maintaining that integration yourself. The work you keep is describing the sequence; the work the platform absorbs is running it reliably. Logic Apps is the glue layer where a file arriving triggers a database write that triggers a notification, all without bespoke long-running server code.
Q: What is the difference between Consumption and Standard Logic Apps?
Consumption runs your workflow in shared multi-tenant infrastructure with no host to manage and bills per action execution, so idle workflows cost almost nothing and a chatty, high-volume workflow gets expensive. Standard runs workflows on a single-tenant runtime hosted on a plan you provision, bills for that hosting plan rather than per action, and adds capabilities Consumption lacks: virtual network integration, private endpoints, in-process built-in connectors, and the stateful-versus-stateless choice. The decision follows the per-action-versus-hosting rule: low-volume, occasional workflows favor Consumption because idle cost is near zero, while high-volume, network-bound, or consolidated workflows favor Standard because a fixed plan cost beats the per-action meter past a break-even point. Estimate metered actions per month and compare against a plan’s monthly cost before committing, because unwinding the choice later means rebuilding.
Q: What is the difference between stateful and stateless workflows?
A stateful workflow persists the inputs and outputs of every action to durable storage as it runs, which gives you the complete run history, the ability to resubmit a failed run, and durability across an infrastructure event mid-run. A stateless workflow holds state in memory only for the life of the run and writes nothing durable, so it finishes faster and handles far more concurrent runs, at the cost of no detailed run history and no mid-run resumption. The choice is available only in the Standard model. Stateful suits workflows you must audit, debug, or resubmit, especially anything touching money or records of record. Stateless suits high-throughput, short-lived, idempotent workflows where latency matters and a failure can be retried cleanly from the start. The mode cannot be toggled after the fact, so choose stateful for anything you expect to operate and troubleshoot.
Q: How do managed connectors and built-in operations differ?
A managed connector runs in shared Microsoft-operated infrastructure outside your workflow’s host, so it works from any plan but adds a network hop and per-call metering. A built-in operation runs in-process inside the Standard runtime, so it is lower latency, avoids the managed-call meter, and can participate in virtual network integration because it runs where your host runs. The managed library is large and reaches hundreds of systems; built-in coverage is narrower but faster and cheaper for the systems it supports. On Standard, the design lever is to prefer a built-in operation when one exists for the system you need and accept the managed connector when only it provides reach. On Consumption every connector call is managed, so the lever there is minimizing the number of connector calls rather than choosing between types.
Q: How does a trigger start a Logic App workflow?
A trigger is the only thing that can start a run, and it evaluates either on a schedule or on an inbound signal. A recurrence trigger fires on a fixed schedule. A request trigger exposes an HTTP endpoint and fires when called. A polling trigger checks a source on an interval and starts a run when it finds new data, advancing a stored cursor so it does not reprocess items. A webhook trigger registers a callback and waits to be notified. When the trigger’s condition is met, the engine creates a run, captures the trigger output as the run’s starting data, and begins executing actions in dependency order. The cursor on a polling trigger is why a paused workflow resumes without reprocessing old data, and why reading the trigger history, separate from run history, is how you tell a trigger that never fired from one that fired and produced a failing run.
Q: How is Logic Apps billed?
Billing follows the plan. On Consumption, the platform meters executions: trigger evaluations, built-in actions, and connector calls each register, at published rates you should verify against the current Azure pricing because they change. Cost is therefore the number of metered events per run multiplied by run frequency, which is why a workflow with many actions, run often or looping over collections, becomes expensive. On Standard, you pay for the hosting plan, the compute it reserves, whether the workflows are busy or idle, so cost is predictable and decoupled from action count. High-volume workflows belong on Standard because a fixed plan cost can run millions of actions without moving, while the Consumption hazard inverts on Standard: an occasional workflow alone on a plan pays the full cost for near-zero work, so consolidate workflows onto one plan to justify the fixed cost.
Q: Why does a Logic App connector suddenly return unauthorized?
A connector returns unauthorized when the connection’s stored credential can no longer produce a valid token, even though the workflow itself is unchanged. OAuth connections to SaaS systems fail when the refresh token expires after the identity provider’s configured lifetime, when the user who authorized it changes their password or is disabled, when consent is revoked, or when a conditional access policy now blocks the grant. The fingerprint is uniformity: every run through that one connection fails the same way starting at a specific time, rather than intermittent failures on one action. The durable fix is to authorize connections with a managed identity wherever the connector supports it, because a managed identity carries no human password lifecycle or interactive consent. For connections that require a user grant, alert on the unauthorized pattern so re-authorization happens before the backlog grows.
Q: Why does my Logic App trigger not fire?
A trigger can appear not to fire for several distinct reasons, each with a different fingerprint in the trigger history. A polling trigger may have advanced its cursor past the item, so it considers the data already seen. The recurrence schedule may not align with when data actually arrives. A concurrency limit may be holding runs in a queue rather than starting them. The connection the trigger uses may have expired, so it cannot poll the source at all. Read the trigger history first, because it records each evaluation and whether it found data, separate from the run history that records what happened once a run started. That distinction tells a trigger that never produced a run from a run that started and then failed, which are two problems with completely different fixes and should not be debugged the same way.
Q: How do I handle errors in a Logic App workflow?
Logic Apps builds error handling from scopes and the run-after configuration rather than a try-catch keyword. You group actions in a scope, then add a second scope configured to run only when the first scope fails, which becomes your catch block. Inside the catch scope you read the failure, log it, send a notification, or run compensating actions. A scope can be set to run after another succeeds, fails, is skipped, or times out, which gives you precise control over the failure path. This is more explicit than exception handling in code: the failure paths are visible on the canvas, which is a strength, but you must build them deliberately rather than relying on a language construct. A workflow with no error-handling scope fails at the first unrecoverable action and stops, which is acceptable for a stateful workflow you will resubmit but dangerous for a stateless one where the run leaves no trace.
Q: How do I control concurrency in a Logic App?
There are two levels of concurrency control. A for-each loop runs its iterations in parallel by default up to a degree of concurrency, which is fast but unordered and can overwhelm a downstream system; you cap that degree, down to one for strictly sequential processing, based on whether order matters and what the target can absorb. Separately, a trigger can limit how many runs of the workflow execute at once, so a burst of triggering events queues rather than starting a stampede of simultaneous runs. The symptom of an unset or wrong concurrency limit is runs stuck in a queued state, which engineers sometimes misread as platform slowness when it is the control doing its job, or downstream throttling when no limit is set. Set loop concurrency to what the target tolerates and workflow concurrency to smooth bursts against shared resources.
Q: What is the maximum run duration for a Logic App?
A single run has a maximum duration enforced by the platform, after which the run is terminated, and the exact value depends on the plan and current limits, so confirm it against the official Azure limits documentation rather than treating any figure as permanent. The design implication is stable regardless of the exact number: a workflow that must wait on a slow external process should not hold a synchronous action open for the entire wait. The pattern that survives the limit is asynchronous. The workflow kicks off the long operation and either ends so a separate trigger resumes the process when it completes, or it uses a polling pattern with a webhook callback so it is not consuming a run’s duration budget while it waits. A naive synchronous version eventually hits the wall when an external call runs long, while the asynchronous design stays comfortably inside the limit.
Q: Can a Logic App connect to resources in a private network?
In the Standard model, yes, natively. A Standard Logic App can integrate with a virtual network and reach private endpoints, so a workflow that must talk to a database, storage account, or service that is not exposed publicly can do so directly. Built-in operations, which run in-process in the Standard runtime, participate in that network integration because they execute where the host runs. The Consumption model does not offer the same native virtual network integration and reaches private resources only through additional infrastructure. This is why a network-bound requirement often decides the plan before cost enters the discussion: if the workload must reach private resources, Standard is frequently the answer regardless of volume. Confirm the specific networking capabilities and any limits against current documentation, since networking features evolve, but the structural point holds that private connectivity is a Standard strength.
Q: How do I reduce the cost of a Logic App?
The levers depend on the plan. On Consumption you reduce metered events: collapse multiple actions into fewer, gate expensive connector calls behind conditions so they run only when needed, and avoid loops that multiply actions across large collections. On Standard you right-size the hosting plan so you are not paying for idle capacity and consolidate several workflows onto one plan so the fixed cost serves real volume. The cross-plan lever is migration: move a workflow from Consumption to Standard at the point where its monthly metered action total crosses the plan’s monthly cost, because past that crossing Consumption is the expensive option. Recognizing the crossing early avoids paying the per-action premium on a workflow that has outgrown it. The first diagnostic for a surprising Consumption bill is a cost report dominated by action executions on one chatty workflow.
Q: How do I debug a failed Logic App run?
Open the run history for the failed run. On a stateful workflow this records the inputs and outputs of every action, so you walk to the first action that failed and read what it received and what error it returned, which usually names the cause directly. If no run appears at all, the failure was in the trigger rather than the actions, so check the trigger history instead, which records each evaluation and whether it found data. The two histories are separate views precisely so you can tell a trigger that never fired from a run that started and failed. On a stateless workflow the run history is thin because step data is not persisted, so debugging leans on telemetry you routed to a monitoring store and on logging the workflow emitted deliberately. This is why stateful is the right default for anything you operate and intend to troubleshoot.
Q: What are control actions in a Logic App?
Control actions shape the flow of a workflow without calling external systems. A condition branches on a boolean, running one path when true and another when false. A switch routes on a value to one of several cases. A for-each iterates over a collection, and an until loops while a condition holds. A scope groups a set of actions so they can be treated as a unit, which matters for error handling because a scope can run conditionally on whether another scope succeeded, failed, was skipped, or timed out. These are the structured-programming primitives expressed as workflow nodes, and they compose the way control flow composes in code. The engine treats each as a node in the dependency graph with inputs, outputs, and a retry policy. Keeping control logic readable, rather than deeply nested, is what keeps a workflow maintainable as it grows.
Q: Should I use a recurrence trigger or an event-driven trigger?
Use a recurrence trigger for genuinely periodic work that has no event mechanism: a nightly export, an hourly reconciliation, a scheduled check of a source that cannot notify you. Use an event-driven trigger, a polling connector trigger, a webhook, or a request trigger, when the source can signal that something happened, because an event-driven trigger runs only when there is work to do. The common misuse is reaching for a tight recurrence as a substitute for an event: a recurrence checking a queue every minute is a polling loop that runs whether or not there is work, metering trigger evaluations on Consumption and burning compute on Standard. When the source emits events, the event-driven trigger wins on both cost and latency because it does not run on an empty interval. Reserve tight recurrence for sources that genuinely offer no better signal.
Q: How does a retry policy work on a Logic App action?
Each action carries its own retry policy, so retries are a local decision you can see and change rather than a global setting. When an action’s call to an external service fails in a retryable way, such as a transient timeout or a throttling response, the engine applies the action’s configured retry policy, retrying with a delay or backoff before treating the failure as final. This is what smooths over brief downstream throttling without manual intervention: an action calling a rate-limited service with a backoff retry recovers from a momentary 429 on its own. Because the policy is per action, an action that aggressively retries against a fragile downstream system is a visible local choice you can tune down, and an action that should fail fast can have retries reduced. Pairing sensible retry policies with concurrency control is how you keep a workflow inside what its downstream systems can absorb.
Q: Can I run multiple workflows in one Logic App?
In the Standard model, yes: one Standard Logic App resource can host many workflows, which share the underlying hosting plan and scale together. This is a core reason consolidation works as a cost strategy, because the plan’s fixed cost is amortized across all the workflows it hosts rather than wasted on a single low-volume flow. In the Consumption model, each Logic App resource holds a single workflow, so there is no in-resource consolidation; cost control on Consumption comes from reducing metered actions rather than sharing a host. The practical implication is that a team with many related integrations often favors Standard specifically so they can group those workflows onto shared plans, right-size the plan to the combined volume, and operate them as a fleet, which is both more economical at scale and simpler to manage than many separate Consumption resources.
Q: What is the difference between Logic Apps and Power Automate?
Power Automate is built on the same underlying workflow engine as Logic Apps, so the trigger-and-actions model and much of the connector library are shared, but they target different audiences and operating models. Power Automate is positioned for business users automating personal and team productivity flows, licensed per user or per flow and managed largely outside the engineering toolchain. Logic Apps is positioned for developers and integration engineers building application-grade workflows, deployed as Azure resources, defined as code, integrated with virtual networks on Standard, and operated with the monitoring and infrastructure rigor of any other Azure service. The practical guidance is to use Power Automate for user-driven productivity automation and Logic Apps for the integration backbone of an application, where you need the deployment pipeline, the networking, the plan-based cost control, and the operational observability that an engineered system requires rather than a citizen-developer experience.
Q: Can one Logic App call another workflow?
Yes, and composing workflows this way is a useful pattern for keeping each workflow focused and reusable. A workflow can invoke another by calling its request-triggered endpoint, passing data in and receiving a response, which lets you factor a shared sub-process, a common validation, a reusable notification, an enrichment step, into its own workflow that several callers reuse rather than duplicating the logic everywhere. The caller treats the callee like any other HTTP-reachable action, so the same endpoint protection applies: the invoked workflow’s request trigger should validate its caller rather than trusting anyone with the URL. The trade-off to weigh is that each invoked workflow is its own run with its own metering on Consumption, so decomposing one workflow into many small called workflows multiplies the metered runs and actions. Factor for reuse and clarity where it pays, but recognize that excessive decomposition on Consumption raises cost the same way any added actions do.