Azure Logic Apps Workflow Generator

VerifiedCaution

Generates production-ready Azure Logic Apps workflows with triggers, connectors, and integration patterns (approval, sync, batch, schedule, event-driven). Helps quickly create enterprise integration workflows in Azure without manually writing ARM/Bicep templates.

Sby Skills Guide Bot
DevelopmentIntermediate
706/2/2026
Claude Code
#azure-logic-apps#integration#workflows#bicep#connectors

Recommended for

Our review

Generates production-ready Azure Logic Apps workflows for enterprise integration patterns such as approvals, data syncs, batch processing, scheduled jobs, and event-driven automation.

Strengths

  • Supports both Consumption (serverless) and Standard (single-tenant) plans
  • Provides detailed Bicep and JSON workflow definitions
  • Covers multiple triggers and connectors (HTTP, Service Bus, Office 365, etc.)
  • Includes security settings like access control and VNet integration

Limitations

  • Requires familiarity with Azure Logic Apps concepts
  • Generated code may need customization for specific environments
  • Does not handle deployment or CI/CD setup
When to use it

When you need to quickly scaffold an Azure Logic App workflow with proper infrastructure as code and integration patterns.

When not to use it

When you need a no-code visual designer or when the logic is highly complex and better suited for traditional development.

Security analysis

Caution
Quality score85/100

The skill includes Bash as an allowed tool, introducing the potential for arbitrary command execution; while the primary purpose is to generate code, the Bash tool could be misused if a user prompts malicious commands.

Findings
  • Bash tool is allowed, which could be used to execute arbitrary commands without explicit restrictions.

Examples

Approval Workflow with HTTP Trigger
Generate an Azure Logic Apps approval workflow triggered by an HTTP request that sends an approval email via Office 365 and writes the result to a SQL Server database.
Scheduled Data Sync with Salesforce
Create a Logic App that runs every hour, fetches new Salesforce leads, and syncs them to Azure SQL Database using the Salesforce connector and SQL Server connector.
Batch Processing with Event Grid
Generate a Logic App that is triggered by Azure Event Grid when a blob is added to a storage account, processes the file content, and sends a notification via Service Bus.

name: azure-logic-apps description: Generate Logic Apps workflows with connectors, triggers, and integration patterns invocation: /azure-logic-apps [pattern] arguments:

  • name: pattern description: "Pattern (approval, sync, batch, schedule, event)" required: false allowed_tools:
  • Read
  • Glob
  • Grep
  • Write
  • Edit
  • Bash

Instructions

You are an Azure Logic Apps integration expert. Generate production-ready Logic Apps workflows for enterprise integration patterns.

Step 1: Gather requirements

Determine from user input or $ARGUMENTS:

  • Pattern: approval workflow, data sync, batch processing, scheduled job, event-driven
  • Plan: Consumption (serverless, pay-per-execution) or Standard (single-tenant, dedicated)
  • Triggers: HTTP request, recurrence, Event Grid, Service Bus, Blob Storage, email
  • Connectors: Office 365, Salesforce, SAP, SQL Server, Dynamics 365, custom APIs
  • Integration: B2B (EDI, AS2, X12), API-based, file-based

Step 2: Generate Consumption Logic App (serverless)

resource logicApp 'Microsoft.Logic/workflows@2019-05-01' = {
  name: 'logic-${appName}-${environment}'
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    state: 'Enabled'
    definition: {
      '$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
      contentVersion: '1.0.0.0'
      parameters: {
        '$connections': {
          defaultValue: {}
          type: 'Object'
        }
        environment: {
          defaultValue: environment
          type: 'String'
        }
      }
      triggers: {}
      actions: {}
      outputs: {}
    }
    parameters: {
      '$connections': {
        value: {}
      }
    }
    accessControl: {
      triggers: {
        allowedCallerIpAddresses: [
          { addressRange: '10.0.0.0/8' }
        ]
      }
      contents: {
        allowedCallerIpAddresses: [
          { addressRange: '10.0.0.0/8' }
        ]
      }
    }
  }
  tags: commonTags
}

Step 3: Generate Standard Logic App (single-tenant)

resource logicAppStandard 'Microsoft.Web/sites@2023-01-01' = {
  name: 'logic-${appName}-${environment}'
  location: location
  kind: 'functionapp,workflowapp'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      netFrameworkVersion: 'v6.0'
      appSettings: [
        { name: 'APP_KIND', value: 'workflowapp' }
        { name: 'AzureFunctionsJobHost__extensionBundle__id', value: 'Microsoft.Azure.Functions.ExtensionBundle.Workflows' }
        { name: 'AzureFunctionsJobHost__extensionBundle__version', value: '[1.*, 2.0.0)' }
        { name: 'AzureWebJobsStorage', value: storageConnectionString }
        { name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
        { name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
        { name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~18' }
      ]
      ftpsState: 'Disabled'
      minTlsVersion: '1.2'
      vnetRouteAllEnabled: true
    }
    virtualNetworkSubnetId: logicAppSubnet.id
    httpsOnly: true
  }
  tags: commonTags
}

// App Service Plan for Standard Logic App
resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: 'asp-logic-${appName}-${environment}'
  location: location
  sku: {
    name: 'WS1'  // WS1, WS2, WS3 (Workflow Standard)
    tier: 'WorkflowStandard'
  }
  properties: {
    zoneRedundant: true
  }
}

Step 4: Generate workflow definitions

HTTP-triggered approval workflow:

{
  "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
  "contentVersion": "1.0.0.0",
  "triggers": {
    "When_a_HTTP_request_is_received": {
      "type": "Request",
      "kind": "Http",
      "inputs": {
        "schema": {
          "type": "object",
          "properties": {
            "requestId": { "type": "string" },
            "requestType": { "type": "string" },
            "requestedBy": { "type": "string" },
            "amount": { "type": "number" },
            "description": { "type": "string" }
          },
          "required": ["requestId", "requestType", "requestedBy", "amount"]
        }
      }
    }
  },
  "actions": {
    "Initialize_status": {
      "type": "InitializeVariable",
      "inputs": {
        "variables": [{
          "name": "approvalStatus",
          "type": "string",
          "value": "Pending"
        }]
      },
      "runAfter": {}
    },
    "Check_amount_threshold": {
      "type": "If",
      "expression": {
        "and": [{
          "greater": ["@triggerBody()?['amount']", 10000]
        }]
      },
      "actions": {
        "Send_VP_approval": {
          "type": "ApiConnectionWebhook",
          "inputs": {
            "host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
            "body": {
              "NotificationUrl": "@{listCallbackUrl()}",
              "Message": {
                "To": "vp@company.com",
                "Subject": "Approval Required: @{triggerBody()?['requestType']} - $@{triggerBody()?['amount']}",
                "Options": "Approve, Reject",
                "Body": "Request from @{triggerBody()?['requestedBy']}: @{triggerBody()?['description']}"
              }
            },
            "path": "/approvalmail/$subscriptions"
          }
        },
        "Set_VP_status": {
          "type": "SetVariable",
          "inputs": { "name": "approvalStatus", "value": "@body('Send_VP_approval')?['SelectedOption']" },
          "runAfter": { "Send_VP_approval": ["Succeeded"] }
        }
      },
      "else": {
        "actions": {
          "Send_manager_approval": {
            "type": "ApiConnectionWebhook",
            "inputs": {
              "host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
              "body": {
                "NotificationUrl": "@{listCallbackUrl()}",
                "Message": {
                  "To": "manager@company.com",
                  "Subject": "Approval Required: @{triggerBody()?['requestType']}",
                  "Options": "Approve, Reject"
                }
              },
              "path": "/approvalmail/$subscriptions"
            }
          },
          "Set_manager_status": {
            "type": "SetVariable",
            "inputs": { "name": "approvalStatus", "value": "@body('Send_manager_approval')?['SelectedOption']" },
            "runAfter": { "Send_manager_approval": ["Succeeded"] }
          }
        }
      },
      "runAfter": { "Initialize_status": ["Succeeded"] }
    },
    "Update_database": {
      "type": "ApiConnection",
      "inputs": {
        "host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
        "method": "patch",
        "path": "/v2/datasets/@{encodeURIComponent('default')}/tables/@{encodeURIComponent('[dbo].[Requests]')}/items/@{encodeURIComponent(triggerBody()?['requestId'])}",
        "body": {
          "Status": "@variables('approvalStatus')",
          "ApprovedDate": "@utcNow()"
        }
      },
      "runAfter": { "Check_amount_threshold": ["Succeeded"] }
    },
    "Send_notification": {
      "type": "ApiConnection",
      "inputs": {
        "host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
        "method": "post",
        "path": "/v2/Mail",
        "body": {
          "To": "@triggerBody()?['requestedBy']",
          "Subject": "Request @{variables('approvalStatus')}: @{triggerBody()?['requestType']}",
          "Body": "<p>Your request has been <b>@{variables('approvalStatus')}</b>.</p>"
        }
      },
      "runAfter": { "Update_database": ["Succeeded"] }
    },
    "Response": {
      "type": "Response",
      "inputs": {
        "statusCode": 200,
        "body": {
          "requestId": "@triggerBody()?['requestId']",
          "status": "@variables('approvalStatus')"
        }
      },
      "runAfter": { "Send_notification": ["Succeeded"] }
    }
  }
}

Scheduled data sync workflow:

{
  "triggers": {
    "Recurrence": {
      "type": "Recurrence",
      "recurrence": {
        "frequency": "Hour",
        "interval": 1,
        "timeZone": "Eastern Standard Time",
        "schedule": {
          "hours": ["8", "9", "10", "11", "12", "13", "14", "15", "16", "17"],
          "minutes": [0]
        }
      }
    }
  },
  "actions": {
    "Get_records_from_Salesforce": {
      "type": "ApiConnection",
      "inputs": {
        "host": { "connection": { "name": "@parameters('$connections')['salesforce']['connectionId']" } },
        "method": "get",
        "path": "/datasets/default/tables/Account/items",
        "queries": {
          "$filter": "LastModifiedDate ge @{addHours(utcNow(), -1)}"
        }
      },
      "runAfter": {}
    },
    "For_each_record": {
      "type": "Foreach",
      "foreach": "@body('Get_records_from_Salesforce')?['value']",
      "actions": {
        "Upsert_to_SQL": {
          "type": "ApiConnection",
          "inputs": {
            "host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
            "method": "post",
            "path": "/v2/datasets/@{encodeURIComponent('default')}/procedures/@{encodeURIComponent('[dbo].[UpsertAccount]')}",
            "body": {
              "AccountId": "@items('For_each_record')?['Id']",
              "AccountName": "@items('For_each_record')?['Name']",
              "LastModified": "@items('For_each_record')?['LastModifiedDate']"
            }
          }
        }
      },
      "operationOptions": "Sequential",
      "runtimeConfiguration": {
        "concurrency": { "repetitions": 20 }
      },
      "runAfter": { "Get_records_from_Salesforce": ["Succeeded"] }
    }
  }
}

Step 5: Error handling patterns

Scope with try-catch:

{
  "actions": {
    "Try_scope": {
      "type": "Scope",
      "actions": {
        "Process_data": {
          "type": "Http",
          "inputs": {
            "method": "POST",
            "uri": "https://api.example.com/process",
            "body": "@triggerBody()",
            "retryPolicy": {
              "type": "exponential",
              "count": 3,
              "interval": "PT10S",
              "minimumInterval": "PT5S",
              "maximumInterval": "PT1H"
            },
            "authentication": {
              "type": "ManagedServiceIdentity",
              "audience": "https://api.example.com"
            }
          }
        }
      },
      "runAfter": {}
    },
    "Catch_scope": {
      "type": "Scope",
      "actions": {
        "Log_error": {
          "type": "Http",
          "inputs": {
            "method": "POST",
            "uri": "https://log-analytics-api.example.com/log",
            "body": {
              "workflowName": "@workflow().name",
              "runId": "@workflow().run.name",
              "error": "@result('Try_scope')",
              "timestamp": "@utcNow()"
            }
          }
        },
        "Send_alert": {
          "type": "ApiConnection",
          "inputs": {
            "host": { "connection": { "name": "@parameters('$connections')['teams']['connectionId']" } },
            "method": "post",
            "path": "/v1.0/teams/@{parameters('teamsChannelId')}/channels/@{parameters('alertChannelId')}/messages",
            "body": {
              "body": {
                "content": "Logic App failure: @{workflow().name} - @{result('Try_scope')[0]['error']['message']}"
              }
            }
          },
          "runAfter": { "Log_error": ["Succeeded"] }
        }
      },
      "runAfter": {
        "Try_scope": ["Failed", "TimedOut"]
      }
    },
    "Finally_scope": {
      "type": "Scope",
      "actions": {
        "Update_audit_log": {
          "type": "ApiConnection",
          "inputs": {
            "host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
            "method": "post",
            "path": "/v2/datasets/@{encodeURIComponent('default')}/tables/@{encodeURIComponent('[dbo].[AuditLog]')}/items",
            "body": {
              "WorkflowName": "@workflow().name",
              "RunId": "@workflow().run.name",
              "Status": "@if(equals(result('Try_scope')[0]['status'], 'Succeeded'), 'Success', 'Failed')",
              "Timestamp": "@utcNow()"
            }
          }
        }
      },
      "runAfter": {
        "Try_scope": ["Succeeded", "Failed", "TimedOut", "Skipped"],
        "Catch_scope": ["Succeeded", "Failed", "TimedOut", "Skipped"]
      }
    }
  }
}

Step 6: Common workflow expressions

# String functions
@concat('Hello, ', triggerBody()?['name'])
@substring('Hello World', 0, 5)                     => 'Hello'
@replace('Hello World', 'World', 'Azure')            => 'Hello Azure'
@toLower(triggerBody()?['email'])
@split('a,b,c', ',')                                => ['a','b','c']

# Date/time functions
@utcNow()                                            => '2024-01-15T10:30:00Z'
@addDays(utcNow(), 7)                                => 7 days from now
@formatDateTime(utcNow(), 'yyyy-MM-dd')              => '2024-01-15'
@convertTimeZone(utcNow(), 'UTC', 'Eastern Standard Time')

# Collection functions
@length(body('Get_items')?['value'])                  => count of items
@first(body('Get_items')?['value'])                   => first item
@last(body('Get_items')?['value'])                    => last item
@contains(createArray('a','b','c'), 'b')              => true

# Control flow
@if(equals(variables('status'), 'Approved'), 'Yes', 'No')
@coalesce(triggerBody()?['name'], 'Unknown')
@empty(triggerBody()?['items'])                       => true if null/empty

# JSON functions
@json('{"key":"value"}')
@xml(body('Get_response'))
@base64(triggerBody()?['file'])

# Workflow functions
@workflow().name                                      => Logic App name
@workflow().run.name                                  => Run ID
@actions('action_name').outputs.statusCode
@result('scope_name')                                 => scope execution results

Step 7: Generate Terraform configuration

# Consumption Logic App
resource "azurerm_logic_app_workflow" "main" {
  name                = "logic-${var.app_name}-${var.environment}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  identity {
    type = "SystemAssigned"
  }

  workflow_parameters = {
    "$connections" = jsonencode({
      defaultValue = {}
      type         = "Object"
    })
  }

  access_control {
    trigger {
      allowed_caller_ip_address_range = ["10.0.0.0/8"]
    }
    content {
      allowed_caller_ip_address_range = ["10.0.0.0/8"]
    }
  }

  tags = var.common_tags
}

# HTTP trigger
resource "azurerm_logic_app_trigger_http_request" "main" {
  name         = "http-trigger"
  logic_app_id = azurerm_logic_app_workflow.main.id

  schema = jsonencode({
    type = "object"
    properties = {
      requestId = { type = "string" }
      data      = { type = "object" }
    }
  })
}

# Recurrence trigger
resource "azurerm_logic_app_trigger_recurrence" "daily" {
  name         = "daily-trigger"
  logic_app_id = azurerm_logic_app_workflow.main.id
  frequency    = "Day"
  interval     = 1
  time_zone    = "Eastern Standard Time"

  schedule {
    at_these_hours   = [8]
    at_these_minutes = [0]
  }
}

# HTTP action
resource "azurerm_logic_app_action_http" "call_api" {
  name         = "call-api"
  logic_app_id = azurerm_logic_app_workflow.main.id
  method       = "POST"
  uri          = "https://api.example.com/process"

  body = jsonencode({
    data = "@triggerBody()"
  })

  headers = {
    "Content-Type" = "application/json"
  }

  run_after {}
}

# Standard Logic App
resource "azurerm_logic_app_standard" "main" {
  name                       = "logic-std-${var.app_name}-${var.environment}"
  location                   = azurerm_resource_group.main.location
  resource_group_name        = azurerm_resource_group.main.name
  app_service_plan_id        = azurerm_service_plan.logic.id
  storage_account_name       = azurerm_storage_account.logic.name
  storage_account_access_key = azurerm_storage_account.logic.primary_access_key
  virtual_network_subnet_id  = azurerm_subnet.logic.id

  identity {
    type = "SystemAssigned"
  }

  site_config {
    dotnet_framework_version         = "v6.0"
    vnet_route_all_enabled           = true
    min_tls_version                  = "1.2"
    ftps_state                       = "Disabled"
    elastic_instance_minimum         = 1
    app_scale_limit                  = 10
    runtime_scale_monitoring_enabled = true
  }

  app_settings = {
    "FUNCTIONS_EXTENSION_VERSION"    = "~4"
    "FUNCTIONS_WORKER_RUNTIME"       = "node"
    "WEBSITE_NODE_DEFAULT_VERSION"   = "~18"
  }

  tags = var.common_tags
}

Step 8: Monitoring and diagnostics

resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: 'logic-diagnostics'
  scope: logicApp
  properties: {
    workspaceId: logAnalyticsWorkspace.id
    logs: [
      { category: 'WorkflowRuntime', enabled: true }
    ]
    metrics: [
      { category: 'AllMetrics', enabled: true }
    ]
  }
}

Key metrics:

  • RunsStarted / RunsCompleted / RunsFailed - Workflow execution stats
  • RunLatency - End-to-end workflow duration
  • ActionLatency - Individual action duration
  • TriggersFired / TriggersSucceeded / TriggersFailed - Trigger health
  • BillableActionExecutions / BillableTriggerExecutions - Cost tracking

Consumption vs Standard comparison

| Feature | Consumption | Standard | |---------|-------------|----------| | Hosting | Serverless, multi-tenant | Single-tenant, App Service | | Pricing | Pay per execution | Fixed plan cost | | VNET | Not supported | Full VNET integration | | Workflows | One per Logic App resource | Multiple per Logic App | | Stateful/Stateless | Stateful only | Both stateful and stateless | | Deployment slots | No | Yes | | Local development | No | VS Code extension | | Scale | Automatic | Configurable (1-10+ instances) | | SLA | 99.9% | 99.95% |

Best practices

  • Use Standard for production - VNET integration, deployment slots, better isolation
  • Implement error handling - Use scopes for try-catch-finally patterns
  • Use managed identity - Authenticate to Azure services without connection strings
  • Parameterize workflows - Use parameters for environment-specific values
  • Enable diagnostic logging - Send logs to Log Analytics for monitoring
  • Use tracked properties - Add custom tracking data to action outputs for querying
  • Limit connector permissions - Use API connections with least-privilege credentials
  • Implement retry policies - Configure exponential backoff for transient failures
  • Use concurrency control - Set runtimeConfiguration.concurrency.repetitions on loops
  • Version workflows - Use ARM/Bicep templates in source control

Anti-patterns

  • Deeply nested conditions - Use Switch actions or separate child workflows
  • Large payloads in workflow state - Use Blob Storage for files; pass references only
  • Polling triggers for real-time needs - Use webhook or push-based triggers
  • Single monolithic workflow - Break into child workflows for maintainability
  • Hardcoded connection strings - Use Key Vault references and managed identity
  • Ignoring run history limits - Consumption retains 90 days; archive if needed
  • Synchronous long-running operations - Use async patterns with webhooks
  • Using Consumption for high-frequency triggers - Cost can exceed Standard plan

Security considerations

  • Restrict trigger access with IP allowlists (accessControl.triggers)
  • Use managed identity for all Azure service connections
  • Secure inputs/outputs with obfuscation (runtimeConfiguration.secureData)
  • Store secrets in Key Vault, not workflow parameters
  • Enable HTTPS-only for Standard Logic Apps
  • Use private endpoints for VNET-connected Logic Apps (Standard)
  • Audit with Azure Monitor and Log Analytics
  • Control access with Azure RBAC (Logic App Contributor, Logic App Operator)

Cost optimization

  • Consumption: Monitor billable executions; optimize loops and conditions to reduce action count
  • Standard: Right-size the App Service Plan; use auto-scale rules
  • Reduce polling frequency: Use longer intervals or event-based triggers
  • Use built-in connectors: They cost less than managed/enterprise connectors
  • Avoid unnecessary actions: Combine expressions instead of using multiple Compose actions
  • Use stateless workflows (Standard): Lower overhead for request-response patterns
  • Archive run history: Configure retention to manage storage costs
  • Disable unused workflows: Stop workflows that are not actively needed
Related skills