Switching Built-in Connections at Runtime
The Problem
Imagine your organization has a single Logic App workflow used by multiple teams. Each team has its own SFTP server, database, or service bus namespace. Traditionally, you'd need separate workflows or hardcode a single connection — neither scales well.
The Solution
Logic Apps Standard supports dynamic connection names for built-in (service provider) connectors. Instead of hardcoding a connection name, you can use any workflow expression — trigger inputs, previous action outputs, parameters, or conditional logic — to determine which connection to use at runtime.
No designer support is available at this time — this works today via Code View.
How It Works
- Define multiple connections in connections.json — one per team/environment/tenant
- Resolve the connection name dynamically using any expression
- Reference that expression in the connectionName field of your service provider action
The runtime evaluates the expression and resolves the connection from connections.json at execution time.
The Key Pattern
"serviceProviderConfiguration": {
"connectionName": "@<expression-that-resolves-to-connection-name>",
"operationId": "listFolder",
"serviceProviderId": "/serviceProviders/Sftp"
}
Instead of hardcoding "connectionName": "sftp", you provide an expression that evaluates to a connection key defined in connections.json.
What You Can Use as the Dynamic Value
| Source | Example |
|---|---|
| Trigger body | @triggerBody()?['connectionName'] |
| Trigger header | @triggerOutputs()['headers']['X-Connection-Name'] |
| Conditional expression | if(equals(triggerBody()?['team'], 'teamA'), 'sftpTeamA', 'sftpTeamB') |
| Previous action output | @outputs('Resolve_Connection') |
| Workflow parameter | @parameters('defaultConnection') |
Step-by-Step Example: Dynamic SFTP Connection
1. Define Connections in connections.json
{
"serviceProviderConnections": {
"sftpTeamA": {
"parameterValues": {
"sshHostAddress": "@appsetting('SftpTeamA_HostAddress')",
"username": "@appsetting('SftpTeamA_Username')",
"password": "@appsetting('SftpTeamA_Password')",
"portNumber": "@appsetting('SftpTeamA_PortNumber')",
"rootDirectory": "@appsetting('SftpTeamA_RootDirectory')"
},
"serviceProvider": {
"id": "/serviceProviders/Sftp"
},
"displayName": "SFTP - Team A"
},
"sftpTeamB": {
"parameterValues": {
"sshHostAddress": "@appsetting('SftpTeamB_HostAddress')",
"username": "@appsetting('SftpTeamB_Username')",
"password": "@appsetting('SftpTeamB_Password')",
"portNumber": "@appsetting('SftpTeamB_PortNumber')",
"rootDirectory": "@appsetting('SftpTeamB_RootDirectory')"
},
"serviceProvider": {
"id": "/serviceProviders/Sftp"
},
"displayName": "SFTP - Team B"
}
}
}
2. Add App Settings
In your Logic App's Configuration → Application settings, add values for each connection:
| Setting | Example Value |
|---|---|
| SftpTeamA_HostAddress | storageacctA.blob.core.windows.net |
| SftpTeamA_Username | storageacctA.localuserA |
| SftpTeamA_Password | (generated password) |
| SftpTeamA_PortNumber | 22 |
| SftpTeamA_RootDirectory | /uploads |
| SftpTeamB_HostAddress | storageacctB.blob.core.windows.net |
| SftpTeamB_Username | storageacctB.localuserB |
| SftpTeamB_Password | (generated password) |
| SftpTeamB_PortNumber | 22 |
| SftpTeamB_RootDirectory | /uploads |
3. Create the Workflow (Code View)
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"List_files_in_folder": {
"type": "ServiceProvider",
"inputs": {
"serviceProviderConfiguration": {
"connectionName": "@if(equals(triggerBody()?['team'], 'teamA'), 'sftpTeamA', 'sftpTeamB')",
"operationId": "listFolder",
"serviceProviderId": "/serviceProviders/Sftp"
},
"parameters": {
"path": "@triggerBody()?['folderPath']"
}
},
"runAfter": {}
},
"Response": {
"type": "Response",
"kind": "Http",
"inputs": {
"statusCode": 200,
"body": "@body('List_files_in_folder')"
},
"runAfter": {
"List_files_in_folder": ["Succeeded"]
}
}
},
"triggers": {
"When_a_HTTP_request_is_received": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {
"type": "object",
"properties": {
"team": { "type": "string" },
"folderPath": { "type": "string" }
}
}
}
}
},
"contentVersion": "1.0.0.0"
},
"kind": "Stateful"
}
4. Test It
Send a POST request to the workflow trigger URL:
{
"team": "teamA",
"folderPath": "/uploads"
}
Change "team": "teamB" to route to the other SFTP server at runtime.
Multi-Step Resolution Example
For more complex logic — lookups, mappings, or multi-condition routing — resolve the connection in a prior action and reference its output:
{
"Resolve_Connection": {
"type": "Compose",
"inputs": "@if(contains(triggerBody()?['region'], 'eu'), 'sftpEurope', if(contains(triggerBody()?['region'], 'us'), 'sftpAmerica', 'sftpDefault'))",
"runAfter": {}
},
"Upload_File": {
"type": "ServiceProvider",
"inputs": {
"serviceProviderConfiguration": {
"connectionName": "@outputs('Resolve_Connection')",
"operationId": "createFile",
"serviceProviderId": "/serviceProviders/Sftp"
},
"parameters": {
"path": "/incoming/data.csv",
"content": "@triggerBody()?['fileContent']"
}
},
"runAfter": {
"Resolve_Connection": ["Succeeded"]
}
}
}
Applicable Connectors
This pattern works with all built-in service provider connectors (type: "ServiceProvider"), including:
- SFTP
- SQL
- Service Bus
- Event Hubs
- Azure Blob Storage (built-in)
- SMTP
- Azure Automation
- And any other built-in connector
Limitations
- Code View only — The designer does not render or edit dynamic connection names visually.
- Built-in connectors only — Managed API connections (type: "ApiConnection") do not support this pattern.
- Connection must exist — The resolved name must match a key already defined in connections.json. Connections cannot be created on-the-fly.
- Case-sensitive — The expression output must exactly match the connection key in connections.json.
Tips
- Use @appsetting() references in connections.json to keep credentials out of source control
- Store passwords in Azure Key Vault referenced via app settings
- Use meaningful connection names (e.g., sftpTeamA, sqlProd, serviceBusDev)
- You can scale to any number of connections — just add entries to connections.json and corresponding app settings
- Inline expressions like @if(...) work directly in connectionName — you don't always need a separate action