Blog Post

Azure Integration Services Blog
6 MIN READ

Demystifying Logic App Standard workflow deployments

jometzg's avatar
jometzg
Icon for Microsoft rankMicrosoft
Apr 07, 2025

As Logic App Standard is built on the App Services runtime, it requires a different approach to automation than the consumption tier.

Automated Deployments

There is currently not much quality information on how to deploy workflows to Logic Apps Standard.

Logic Apps Standard is built on the Azure Functions runtime and unlike Logic Apps Consumption, there can be any number of workflows for one Logic App Standard.

A comparison of these two versions is here.

Like Azure Functions, the best deployment approach for these is to:

  1. Deploy the Logic App Standard infrastructure
  2. Deploy each workflow separately from the infrastructure as the rate of change of these is much higher than the infrastructure.

For a Logic App that has multiple workflows, you can make the decision to deploy all of the workflows in one go or each workflow separately. This is very much akin to Azure Functions an aligns with a (micro) services approach as opposed to a monolith deployment approach.

Steps to Deployment

In general, deployment is done in two halves:

  1. Infrastructure
  2. Workflows

Apart from the processes being different, the main reason for this separation is that usually workflow deployments - like any code deployment tend to happen at a higher frequency than infrastructure deployments.

Infrastructure Deployment

There are many routes to this:

  1. CLI
  2. Developer CLI (azd)
  3. ARM template
  4. Bicep
  5. Terraform.

It is best to align this with the overall approach that is other use on adjacent projects or organisational standards for most skills reuse.

This is how a Logic Apps Standard may be deployed using Bicep

There are broadly-speaking 4 main components:

  1. the Logic App itself
  2. the server farm on which the Logic App is deployed (this may be shared)
  3. A storage account for state management
  4. Optionally Application Insights

Some sample bicep

the server farm example

resource serverfarms_ASP_towerhamletsrg_97bc_name_resource 'Microsoft.Web/serverfarms@2024-04-01' = { name: serverfarms_ASP_towerhamletsrg_97bc_name location: 'UK South' sku: { name: 'WS1' tier: 'WorkflowStandard' size: 'WS1' family: 'WS' capacity: 1 } kind: 'elastic' properties: { perSiteScaling: false elasticScaleEnabled: true maximumElasticWorkerCount: 20 isSpot: false reserved: false isXenon: false hyperV: false targetWorkerCount: 0 targetWorkerSizeId: 0 zoneRedundant: false } }

the Logic App

resource sites_jjblankthree_name_resource 'Microsoft.Web/sites@2024-04-01' = { name: sites_jjblankthree_name location: 'UK South' kind: 'functionapp,workflowapp' identity: { type: 'SystemAssigned' } properties: { enabled: true hostNameSslStates: [ { name: '${sites_jjblankthree_name}.azurewebsites.net' sslState: 'Disabled' hostType: 'Standard' } { name: '${sites_jjblankthree_name}.scm.azurewebsites.net' sslState: 'Disabled' hostType: 'Repository' } ] serverFarmId: serverfarms_ASP_towerhamletsrg_97bc_externalid reserved: false isXenon: false hyperV: false dnsConfiguration: {} vnetRouteAllEnabled: false vnetImagePullEnabled: false vnetContentShareEnabled: false siteConfig: { numberOfWorkers: 1 acrUseManagedIdentityCreds: false alwaysOn: false http20Enabled: false functionAppScaleLimit: 0 minimumElasticInstanceCount: 1 } scmSiteAlsoStopped: false clientAffinityEnabled: false clientCertEnabled: false clientCertMode: 'Required' hostNamesDisabled: false ipMode: 'IPv4' vnetBackupRestoreEnabled: false customDomainVerificationId: '7C6761218AA3FF18AC28235A2C8C88C2CB16915F3086640269C352A8D052E5CF' containerSize: 1536 dailyMemoryTimeQuota: 0 httpsOnly: true endToEndEncryptionEnabled: false redundancyMode: 'None' publicNetworkAccess: 'Enabled' storageAccountRequired: false keyVaultReferenceIdentity: 'SystemAssigned' } }

storage for state management:

resource logicAppStorage 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: logicAppStorageName location: location kind: 'StorageV2' sku: { name: storageAccountSku } properties: { allowBlobPublicAccess: false accessTier: 'Hot' supportsHttpsTrafficOnly: true minimumTlsVersion: 'TLS1_2' } }

Application Insights

resource applicationInsightsLogicApp 'Microsoft.Insights/components@2020-02-02' = { name: 'appinss-${key}-${env}' location: location kind: 'web' properties: { Application_Type: 'web' Flow_Type: 'Bluefield' publicNetworkAccessForIngestion: 'Enabled' publicNetworkAccessForQuery: 'Enabled' Request_Source: 'rest' RetentionInDays: 30 WorkspaceResourceId: logAnalyticsWorkspacelogicApp.id } }

Workflow Deployment

As the Logic Apps run under the Azure Functions runtime, the Azure Functions deployment mechanisms may be used. These mechanisms are traditionally used for code deployments, but can also deploy the workflow definitions.

What needs to be deployed

There are three or four components to a Logic App definition:

  1. hosts.json
  2. connections.json
  3. workflow.json
  4. parameters.json (this is optional)

The hosts file is pretty standard and just defines the runtime and versions that the logic apps run under.

The connections.json contains references to the connections to other services that any of the workflows may need. These work alongside some App Settings which will actually define connection strings to these remote services. For a deployed workflow to work, all of the connections used need to be defined and these connections span all of the workflows for that Logic App.

The parameters.json file is a list of parameters that may be referenced in the workflow definition. If there are parameters in any of the workflows, then this file needs to be deployed. 

Each workflow itself needs to be defined in its own workflow.json file. Therefore if there are multiple workflows to be deployed, then each of these needs to be in its own folder and each named workflow.json.

How to deploy

There is already a GitHub Action zip deploy for Azure Functions.

This can be used for Logic Apps Standard workflow deployments. In order to use this, a zip file needs to be created that conforms to a standard structure:

Logic App Standard Workflow files

Steps in GitHub Action

Firstly use an action to copy the files to a known place output for the zip deploy step:

- name: Create project folder run: | mkdir output cp 'logicapps/host.json' 'output/' cp 'logicapps/connections.json' 'output/' cp -r 'workflows/copy-blob' 'output/' cp -r 'workflows/move-blobs' 'output/'

Then the action to zip the above structure needs to be performed:

- name: Easy Zip Files uses: papeloto/action-zip@v1 with: dest: '${{ github.run_id }}.zip' files: output/

this zip file is then used to deploy to the logic app

- name: 'Run Azure Functions Action' uses: Azure/functions-action@v1 id: fa with: app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }} package: '${{ github.run_id }}.zip'

App Settings may be created in a couple of ways:

 - name: Create app settings
      uses: azure/appservice-settings@v1
      with:
        app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
        app-settings-json: '${{ secrets.APP_SETTINGS }}'

In the above, all of the App Settings that relate to the connections as a piece of JSON are put into a GitHub secret called APP_SETTINGS. These are then deployed in one go.

An alternative approach is to put each individual secret as its own secret in GitHub and pass these into the app service like below:

- name: Set Function App secret
      run: |
        az functionapp config appsettings set \
          --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
          --resource-group ${{ env.AZURE_RESOURCER_GROUP_NAME }}  \
          --settings <SettingName>=${{ secrets.<SecretName> }}

In the above a specific setting is set from a specific secret.

A combination of the two may be done, which is to set most of the settings that do not contain secrets from a configuration file (settings.json) and then separately set the secrets using the above method.

- name: Set Function App settings from file
      run: |
        az functionapp config appsettings set \
          --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
          --resource-group ${{ env.AZURE_RESOURCER_GROUP_NAME }} \
          --settings .json

Deployed Logic App Workflows

Once this has been run, the Logic App should have these workflows present.

These reference connections:

which references an App Setting

Understanding the relationship between workflows, connections and App Settings

In a Logic App Standard, connections are common across all workflows. Each workflow then references connections as needed.

Here is the JSON definition of a connection

{ "serviceProviderConnections": { "AzureBlob": { "parameterValues": { "connectionString": "@appsetting('AzureBlob_connectionString')" }, "parameterSetName": "connectionString", "serviceProvider": { "id": "/serviceProviders/AzureBlob" }, "displayName": "source-container" } }, "managedApiConnections": {} }

As can be seen from the above, the connection string is not kept in the connections.json, but references an App Setting and it is this App Setting that contains the connection string.

So, in deployment terms any secrets will only be in App Settings. 

An extended approach would be to use App Service Key Vault references 

.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret)

In this manner, secrets will be in key vault and the Logic App Standard runtime will fetch these values from key vault. It is important to remember that for this to work, the Logic App must have a managed identity and a role assignment that allows the Logic App to read key vault secrets.

Debugging Deployments

There are quite a few ways in which this can go wrong. Here are some hints:

  1. check the Action run and that all steps are executing and the run is green.
  2. Check the logic app to see if the workflows and connections are present
  3. Check that there is an App Setting per connection - as it is this that holds the connection information
  4. Check Kudu to see if you see the file structure you are expecting
Kudu view of workflow deployment files

5. If secrets are used and these reference key vault, then the portal experience will show if the Logic App can retrieve the named secret. A green tick will show a valid reference, otherwise it will be coloured red and you may need to follow troubleshooting key vault references

Sample Code

There is a GitHub repository that explains this in detail with a worked example of a Logic App Standard and its deployment using a GitHub Action.

Summary and Take-Aways

Logic App Standard allows separation of infrastructure from workflow deployments.

Automated workflow deployment uses the Azure Functions "zip deploy" GitHub Action to deploy workflows. The zip file that needs to be created as part of the build process has a very specific structure that needs to be followed for the workflows to be deployed correctly.

Configuration settings and secrets end up in the App Settings part of Environment Variables menu in the portal experience of Logic App Standard. These settings can be deployed all as one large JSON secret or individually.

These secrets can even be key vault references to improve security - with some extra configuration.

Updated Apr 02, 2025
Version 1.0