Registers one Azure (fully managed) integration runtime on a Synapse workspace β the Microsoft-hosted compute a data flow or a copy activity runs on. Targets
hashicorp/azurerm ~> 4.0.
- π§© Creates one
azurerm_synapse_integration_runtime_azureβ a named, Microsoft-hosted runtime on the workspace. - π© Leads with a defect in the provider itself: its name error message states a rule its regular expression does not enforce. The message says "no consecutive dashes"; the pattern permits them, verified against the pattern.
- βοΈ Documents the mirror-image defect on the self-hosted sibling β same message text, different pattern, wrong about the opposite half.
- π’ States that
core_countis a closed set, not a range: 8, 16, 32, 48, 80, 144 or 272, with large steps between them. - βοΈ Explains that
time_to_live_mindefaults to 0, which means no cluster reuse at all β every data flow pays a cold start β and that the provider validates this field with nothing. - π― Warns that the three compute settings govern data flows only, so tuning them changes nothing for a copy-only pipeline.
- π Notes that
AutoResolvemoves the data-residency decision out of your Terraform and into run time. - π·οΈ Carries no
tagsβ the resource has none. The universal tail istimeoutsonly.
π‘ Why it matters: a managed runtime is easy to create and easy to misjudge. The default is a cluster that is torn down after every activity, so the first thing people notice is that data flows are slow; the fix is one field the provider does not validate at all. Meanwhile the compute settings that look like the tuning surface are ignored entirely by a copy activity, so a cost investigation that starts here finds nothing to explain.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- β Star this repository to help others discover this Terraform module.
- π€ Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- β Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
flowchart TB
rg["terraform-azurerm-resource-group"]
ws["terraform-azurerm-synapse-workspace"]
this["terraform-azurerm-synapse-integration-runtime-azure"]
shir["terraform-azurerm-synapse-integration-runtime-self-hosted"]
sqlp["terraform-azurerm-synapse-sql-pool"]
spark["terraform-azurerm-synapse-spark-pool"]
aad["terraform-azurerm-synapse-workspace-aad-admin"]
rg -->|"name"| ws
ws -->|"id"| this
ws -->|"id"| shir
ws -->|"id"| sqlp
ws -->|"id"| spark
ws -->|"id"| aad
this -->|"name, selected by a pipeline activity"| ws
shir -->|"the other runtime type, for data Azure cannot reach"| ws
classDef me fill:#0078D4,stroke:#004578,color:#ffffff;
classDef keystone fill:#004578,stroke:#002b4d,color:#ffffff;
classDef sib fill:#eef3f8,stroke:#b9c7d6,color:#1b2a3a;
class this me;
class ws keystone;
class rg,shir,sqlp,spark,aad sib;
The edge back to the workspace is not a Terraform reference: a pipeline activity selects a runtime by name, as a string in its own definition. Nothing here reports that no activity uses this runtime, and nothing reports that one names a runtime that does not exist.
flowchart TB
subgraph inputs["Inputs"]
ident["name plus synapse_workspace_id, both force-new"]
loc["location, force-new, AutoResolve or a region"]
compute["compute_type, core_count, time_to_live_min -- data flows only"]
desc["description"]
end
this["azurerm_synapse_integration_runtime_azure.this"]
subgraph outputs["Outputs"]
oid["id, name, synapse_workspace_id, synapse_workspace_name, resource_group_name"]
oloc["location, region_is_resolved_at_run_time"]
ocomp["compute_type, core_count, time_to_live_min, cluster_is_torn_down_after_every_activity"]
ofact["name_uses_consecutive_dashes, the_two_runtime_types_do_not_share_a_name_rule, creating_this_starts_no_compute"]
end
ident --> this
loc -->|"AutoResolve defers the residency decision to run time"| this
compute -->|"ignored entirely by a copy activity"| this
desc --> this
this --> oid
this --> oloc
this --> ocomp
this --> ofact
classDef me fill:#0078D4,stroke:#004578,color:#ffffff;
classDef sib fill:#eef3f8,stroke:#b9c7d6,color:#1b2a3a;
class this me;
class ident,loc,compute,desc,oid,oloc,ocomp,ofact sib;
Resource inventory
| Resource | Count | Notes |
|---|---|---|
azurerm_synapse_integration_runtime_azure |
1 | The keystone this. No children β a runtime owns nothing. |
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/azurerm |
~> 4.0 |
| Provider block | None in this module β the caller configures the provider, its authentication, and the mandatory features {} block. |
Schema notes that bite
- π΄ The provider's name error message states a rule its regular expression does not enforce. The message says "no consecutive dashes"; the pattern permits them. The three-character minimum the same message claims is enforced. This module mirrors the pattern and reports the gap.
- π΄ The self-hosted sibling carries the same message and a different pattern, wrong about the opposite half: it forbids consecutive dashes and accepts a one-character name.
core_countis a closed set β 8, 16, 32, 48, 80, 144, 272 β not a range. An intermediate value is rejected rather than rounded, and 80 to 144 is nearly double.time_to_live_minis validated by nothing at all and defaults to 0, which means no cluster reuse.compute_typeis case-sensitive PascalCase:General,ComputeOptimized,MemoryOptimized.locationaccepts the literalAutoResolveor a region, and the region half falls back to a plain non-empty check when the provider has not fetched Azure's location list β so the same value can pass in one run and fail in another. A region is normalised and diff-suppressed on the normalised form.- The three compute settings are sent inside the data-flow properties, so a copy-only pipeline uses this runtime without touching any of them.
- Three force-new fields, all declared on the resource itself:
name,synapse_workspace_id,location. - This resource does have an existence check on create β an apply over an existing runtime fails and tells you to import.
- No
tags. Thelocationhere is where the compute runs, not an ARM resource location.
Least-privilege, at the smallest scope that works:
Microsoft.Synapse/workspaces/integrationRuntimes/writeand.../integrationRuntimes/deleteon the target workspace. A custom role scoped to the workspace is enough; Contributor on the workspace, or on its resource group, covers this more broadly than necessary.Microsoft.Synapse/workspaces/integrationRuntimes/readon the workspace, for the existence check before creating and for every refresh.
βΉοΈ Plan access is not credential access on this resource. A managed runtime holds no key, and the provider marks nothing on it sensitive. That is not true of the self-hosted sibling, whose refresh reads two authorization keys β see example 11.
- An existing Synapse workspace (the
synapse-workspacemodule). - A region that can host the requested compute, if
locationis pinned rather than left atAutoResolve. Nothing here checks that a region can supply the requestedcore_count, and the failure arrives when an activity runs rather than at apply. - A pipeline or data flow that selects this runtime by name, if it is to do anything. The registration alone runs nothing and costs nothing.
- The caller configures the
provider "azurerm" { features {} }block, auth, and subscription.
terraform-azurerm-synapse-integration-runtime-azure/
βββ providers.tf # required_version and the pinned azurerm; no provider block
βββ variables.tf # identity, location, the three compute settings, description, timeouts
βββ main.tf # the single keystone azurerm_synapse_integration_runtime_azure.this
βββ outputs.tf # id first, then identity and compute, then the quiet facts
βββ README.md # this file
βββ SCOPE.md # the cross-module contract
βββ LICENSE # MIT
βββ .gitignore
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
}
β οΈ The caller configuresprovider "azurerm" { features {} }, its authentication, and its subscription. This module declares no provider block.
βοΈ This call gives you a cluster that is torn down after every activity, because
time_to_live_mindefaults to 0. That is the provider's default and it is rarely what you want. See example 4.
Consumes
| Input | Type | Source |
|---|---|---|
synapse_workspace_id |
string |
terraform-azurerm-synapse-workspace output id |
Emits
| Output | Consumed by |
|---|---|
id |
management locks, role assignments, review |
name |
the pipeline activity that selects this runtime |
cluster_is_torn_down_after_every_activity |
performance review |
region_is_resolved_at_run_time |
residency review |
name_uses_consecutive_dashes |
naming review |
1 Β· The smallest real call
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
}π‘ The three compute settings are omitted, so the provider's defaults apply:
General, 8 cores, and a time-to-live of 0.
2 Β· Letting Azure choose the region
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-auto"
synapse_workspace_id = var.synapse_workspace_id
location = "AutoResolve" # exact casing; see example 3
}
output "residency_decided_elsewhere" {
value = module.dataflow_runtime.region_is_resolved_at_run_time
}
β οΈ AutoResolvemoves a data-residency decision out of your Terraform. The compute region is chosen per run from the sink's location, so where the data is processed is decided at run time by the pipeline, not here. Pin a region where residency is a requirement rather than a preference.
3 Β· Why the casing of `AutoResolve` matters
# REJECTED at terraform plan, offline and without credentials:
# location = "autoresolve"
#
# Error: location must be spelled "AutoResolve" in exactly that casing.
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-auto"
synapse_workspace_id = var.synapse_workspace_id
location = "AutoResolve"
}
# ACCEPTED -- a region may be written any way you like:
# location = "East US 2" -> normalised to "eastus2" by the providerβΉοΈ The provider special-cases the exact string
AutoResolveand hands anything else to its region check β which compares against a location list fetched from Azure and falls back to a plain non-empty check when that list has not been fetched. Soautoresolvepasses or fails depending on connectivity. A region name has no such problem.
4 Β· The default that makes data flows slow
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
# Keep the cluster warm between activities. The provider's default is 0.
time_to_live_min = 15
}
output "cold_start_every_time" {
value = module.dataflow_runtime.cluster_is_torn_down_after_every_activity
}βοΈ
time_to_live_min = 0means no cluster reuse. Every data-flow activity pays a cold start measured in minutes rather than seconds, so a pipeline of many short data flows spends most of its wall-clock time starting clusters.
π° The trade is real in both directions: a warm cluster is billed for the whole time it stays warm. Pick the TTL from how closely your activities follow each other, not from a round number.
β οΈ The provider applies no validation at all to this field β no minimum, no maximum. This module rejects a negative value because none is meaningful, and deliberately does not invent an upper bound.
5 Β· `core_count` is a set, not a dial
# REJECTED at terraform plan, offline and without credentials:
# core_count = 64
#
# Error: core_count must be one of 8, 16, 32, 48, 80, 144 or 272.
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
core_count = 48 # 8, 16, 32, 48, 80, 144, 272 -- nothing between
time_to_live_min = 15
}
β οΈ The steps get large: 48 to 80 is two thirds bigger, and 80 to 144 is nearly double. "A bit more compute" is not available β the next size up is the only option, and it is what the bill will reflect.
6 Β· Compute shape, and what it does not affect
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
compute_type = "MemoryOptimized" # PascalCase; "memoryoptimized" is rejected
core_count = 32
time_to_live_min = 20
}
output "these_settings_are_data_flow_only" {
value = module.dataflow_runtime.compute_settings_govern_data_flows_only
}π¨ All three compute settings govern data flows only. They are sent inside the runtime's data-flow properties, so a pipeline that runs copy activities and no data flow uses this runtime without touching any of them. Tuning them to fix a slow copy changes nothing, and a cost investigation that starts here will find nothing to explain.
7 Β· The name rule the provider misdocuments
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
# ACCEPTED here, even though the provider's own error message says
# "no consecutive dashes" -- its regular expression permits them.
name = "ir--dataflow"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
}
output "relying_on_a_provider_gap" {
value = module.dataflow_runtime.name_uses_consecutive_dashes
}π© This module mirrors the provider's pattern, not its message. A rule the provider does not enforce may be one Azure does not enforce either, and a
validation {}failure would blockterraform destroyas well as apply β so the condition is reported rather than refused.
β οΈ Atruehere means you are relying on that gap. The self-hosted sibling would reject the same name. Prefer single dashes and the question does not arise.
8 Β· Two runtimes, two different name rules
# The AZURE runtime: minimum 3 characters ENFORCED, consecutive dashes PERMITTED.
# "ir--dataflow" accepted
# "ab" rejected
# The SELF-HOSTED runtime: consecutive dashes REJECTED, one-character name ACCEPTED.
# "ir--onprem" rejected
# "i" accepted
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod" # legal on both
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
}
output "do_not_assume_one_convention" {
value = module.dataflow_runtime.the_two_runtime_types_do_not_share_a_name_rule
}βΉοΈ Both resources carry the same error message text and different regular expressions, and each message is wrong about the opposite half. A naming convention validated against one is not validated against the other. A name of at least three characters using only single dashes is legal on both, which is the convention worth adopting.
9 Β· Several runtimes for different workloads
locals {
runtimes = {
"ir-dataflow-heavy" = { compute_type = "MemoryOptimized", core_count = 80, ttl = 30 }
"ir-dataflow-light" = { compute_type = "General", core_count = 8, ttl = 10 }
"ir-copy-only" = { compute_type = "General", core_count = 8, ttl = 0 }
}
}
module "dataflow_runtimes" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
for_each = local.runtimes
name = each.key
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
compute_type = each.value.compute_type
core_count = each.value.core_count
time_to_live_min = each.value.ttl
}
output "which_runtimes_cold_start" {
value = { for k, m in module.dataflow_runtimes : k => m.cluster_is_torn_down_after_every_activity }
}π‘ The
ir-copy-onlyentry leaves the TTL at 0 deliberately: a copy activity does not use the data-flow cluster, so keeping one warm for it would be paying for nothing.
β οΈ The map key becomes thename, which is force-new. Renaming a key destroys one runtime and creates another β and every pipeline that named the old one is now pointing at nothing, with no plan reporting it.
10 Β· Moving a runtime, and what forces replacement
output "what_replaces_this_runtime" {
value = module.dataflow_runtime.force_new_fields
}# All three of these are force-new:
# name -- and pipelines name the runtime by this string
# synapse_workspace_id -- a runtime belongs to one workspace
# location -- the compute region cannot be moved in place
#
# The compute settings and the description all update in place, which is what
# makes tuning safe and renaming not.
β οΈ Changinglocationfrom a pinned region toAutoResolve, or between regions, is a replacement rather than a reconfiguration.
11 Β· This is not the self-hosted runtime
# THIS module -> azurerm_synapse_integration_runtime_azure
# Microsoft-hosted compute, with a region and a core count. No credentials.
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = var.synapse_workspace_id
location = "eastus2"
}
# The SIBLING -> azurerm_synapse_integration_runtime_self_hosted
# A REGISTRATION for compute you run yourself, to reach data Azure cannot.
# No location, no core count -- and two authorization keys that the provider
# reads on EVERY refresh and marks sensitive on NEITHER.
module "onprem_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-self-hosted.git?ref=v1.0.0"
name = "ir-onprem-sql"
synapse_workspace_id = var.synapse_workspace_id
}π The difference that matters operationally: plan access on the self-hosted runtime is credential access, and on this one it is not. Reach for this module for compute in Azure, and for the sibling only when the data is somewhere Azure cannot reach.
12 Β· Reviewing cost and residency across environments
output "runtime_review" {
value = {
workspace = module.dataflow_runtime.synapse_workspace_name
resource_group = module.dataflow_runtime.resource_group_name
region = module.dataflow_runtime.location
auto_region = module.dataflow_runtime.region_is_resolved_at_run_time
compute = module.dataflow_runtime.compute_type
cores = module.dataflow_runtime.core_count
warm_minutes = module.dataflow_runtime.time_to_live_min
cold_start_each = module.dataflow_runtime.cluster_is_torn_down_after_every_activity
}
}π‘
coresandwarm_minutestogether are the cost shape of a data-flow cluster: it is charged per core-hour while it is up.cold_start_eachis the performance shape. The two pull in opposite directions, which is exactly why both are emitted rather than one being defaulted to an opinion.
13 Β· ποΈ End-to-end composition
module "data_rg" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"
name = "rg-data-platform"
location = "eastus2"
tags = {
environment = "prod"
owner = "data-platform-team"
}
}
module "synapse" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-workspace.git?ref=v1.0.0"
name = "syn-platform-prod"
resource_group_name = module.data_rg.name
location = module.data_rg.location
storage_data_lake_gen2_filesystem_id = var.filesystem_id
azuread_authentication_only = true
public_network_access_enabled = false
tags = module.data_rg.tags
}
module "workspace_admin" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-workspace-aad-admin.git?ref=v1.0.0"
synapse_workspace_id = module.synapse.id
login = "Synapse Platform Admins"
object_id = var.platform_admins_group_object_id
tenant_id = var.tenant_id
}
# Managed compute, pinned to the workspace's region and kept warm.
module "dataflow_runtime" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-integration-runtime-azure.git?ref=v1.0.0"
name = "ir-dataflow-prod"
synapse_workspace_id = module.synapse.id
location = module.data_rg.location
compute_type = "MemoryOptimized"
core_count = 32
time_to_live_min = 20
description = "Data-flow compute for the nightly warehouse load. Cost owner: data-platform-team."
}
module "warehouse" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-synapse-sql-pool.git?ref=v1.0.0"
name = "dwmain"
synapse_workspace_id = module.synapse.id
sku_name = "DW100c"
tags = module.data_rg.tags
}
output "runtime_name_for_pipeline_definitions" {
value = module.dataflow_runtime.name
}
output "runtime_keeps_a_warm_cluster" {
value = !module.dataflow_runtime.cluster_is_torn_down_after_every_activity
}π‘ The runtime takes
module.data_rg.location, so the compute runs in the same region as the workspace and the warehouse rather than wherever a sink happens to be. That is a residency decision made here, on purpose, instead of at run time.
π¨ Nothing in this composition makes a pipeline use the runtime. An activity selects it by the string in
runtime_name_for_pipeline_definitions, in a pipeline definition Terraform does not own β so wire that output through rather than retyping the name.
Identity β name and synapse_workspace_id, both required and both force-new.
Placement β location, required and force-new. AutoResolve or a region.
Compute β compute_type, core_count and time_to_live_min, all optional, all in-place, and all
data-flow only.
Universal tail β timeouts only. This resource has no tags.
Full input schema
| Name | Type | Default | Required | Notes |
|---|---|---|---|---|
name |
string |
β | yes | At least 3 chars, letters, numbers and dashes, first and last alphanumeric. Force-new. Consecutive dashes are permitted by the provider despite its message. |
synapse_workspace_id |
string |
β | yes | Full Synapse workspace Resource ID, anchored at both ends. Force-new. |
location |
string |
β | yes | "AutoResolve" (exact casing) or an Azure region in any casing. Force-new. |
compute_type |
string |
null β provider default "General" |
no | "General", "ComputeOptimized" or "MemoryOptimized", PascalCase. Data flows only. |
core_count |
number |
null β provider default 8 |
no | One of 8, 16, 32, 48, 80, 144, 272. A closed set, not a range. Data flows only. |
time_to_live_min |
number |
null β provider default 0 |
no | Whole minutes, zero or greater. 0 means no cluster reuse. The provider validates this field with nothing. |
description |
string |
null |
no | Free text. Must be non-empty when supplied. |
timeouts |
object({ create, read, update, delete }) |
null |
no | Go duration strings. Provider defaults: create 30m, read 5m, update 30m, delete 30m. |
β οΈ A key not declared in thetimeoutsobject type is silently discarded by Terraform's type conversion rather than reported β a misspelled key produces no error and no timeout.
| Output | Description | Notes |
|---|---|---|
id |
Resource ID of the runtime | Emitted first |
name |
The string a pipeline names to select this runtime | Force-new |
synapse_workspace_id |
The parent workspace, as Azure holds it | Rebuilt from the record's own ID |
synapse_workspace_name |
Workspace name, parsed from that ID | Derived locally |
resource_group_name |
Resource group, parsed from that ID | Derived locally |
location |
AutoResolve or a normalised region |
Force-new |
region_is_resolved_at_run_time |
True when location is AutoResolve |
Residency review |
compute_type |
Data-flow compute shape | Data flows only |
core_count |
Cores for the data-flow compute | Cost review |
time_to_live_min |
Warm-cluster minutes | Cost review |
cluster_is_torn_down_after_every_activity |
True when the TTL is 0 | Performance review |
description |
The description as Azure holds it | null when unset |
name_uses_consecutive_dashes |
True when the name relies on a provider gap | Naming review |
the_two_runtime_types_do_not_share_a_name_rule |
Constant true |
Naming review |
compute_settings_govern_data_flows_only |
Constant true |
Read this one first |
creating_this_starts_no_compute |
Constant true |
Design review |
force_new_fields |
["name", "synapse_workspace_id", "location"] |
Change planning |
fields_azure_returns_on_read |
The fields in which drift is detectable at all | Drift review |
this_resource_supports_no_azure_resource_tags |
Constant true |
Tagging policy |
π No secret is emitted, because this resource holds none.
The provider misdocuments its own name rule, and this module mirrors the rule rather than the
documentation. The error message on name states that consecutive dashes are not allowed. Its regular
expression permits them β that was checked against the pattern itself rather than taken on trust. This module
reproduces the pattern character for character and reports the condition through
name_uses_consecutive_dashes instead of adding the missing check, because a rule the provider does not
enforce may be one Azure does not enforce either, and a validation {} failure blocks terraform destroy as
well as apply. The same message on the self-hosted sibling is wrong about the opposite half, which is why
neither runtime's name rule can be inferred from the other's.
The default is a cluster that never survives an activity. time_to_live_min defaults to 0, so a data
flow starts a cluster, runs, and tears it down. For a pipeline of many short data flows, most of the
wall-clock time is cluster startup. The fix is a single field β and the provider applies no validation to it
at all, no minimum and no maximum, so nothing pushes back on a value of 0 or 6000. This module rejects a
negative value because none is meaningful and deliberately does not invent a ceiling: the upper bound is a
cost decision, and a warm cluster is billed for every minute it stays warm.
Two of the three compute settings look like general tuning and are not. compute_type, core_count and
time_to_live_min are all sent inside the runtime's data-flow properties. A copy activity assigned to this
runtime uses none of them. That makes a whole class of investigation dead-ended from the start: raising
core_count to speed up a slow copy changes nothing, and a bill attributed to this runtime is a data-flow
bill or nothing at all.
core_count is a set with large gaps. 8, 16, 32, 48, 80, 144, 272. There is no intermediate value to
reach for, so the decision is always which step, and the steps near the top nearly double. The module mirrors
the provider's set exactly rather than approximating it as a range.
AutoResolve is a residency decision, made elsewhere. It is a legitimate and convenient choice, and it
means the compute region is selected per run from the sink's location rather than fixed by this
configuration. Where residency is a requirement rather than a preference, pin the region β and
region_is_resolved_at_run_time exists so that a review can tell the two apart without reading the value.
Creating this record starts nothing. It is a definition. The cluster starts when an activity runs, which makes an apply here fast and free β and also means an apply proves nothing about whether the compute can actually start. A region that cannot supply the requested core count fails at run time.
| Concern | Default in this module | Opt-out |
|---|---|---|
| The name pattern | Mirrors the provider's regex, not its message. The consecutive-dash rule the message claims is reported, never enforced | β |
compute_type / core_count |
Validated against the provider's own closed sets, with the sets named in the error messages | β |
time_to_live_min |
Negative rejected; no upper bound invented β the ceiling is a cost decision, not a published limit | β |
location casing |
Only the near miss is rejected: a differently-cased autoresolve, whose acceptance depends on connectivity |
β |
| Region set | Never enumerated. The set changes, and a validation {} failure blocks terraform destroy as well as apply |
β |
| Provider defaults | Left in place. Omitting a compute setting sends nothing, so an empty call behaves exactly as the provider documents | set the field |
| Cost and performance | Reported through derived outputs rather than defaulted to an opinion β the two pull in opposite directions | β |
tags |
Not offered β the resource has none. Tag the workspace | β |
π There is no secret on this resource and no secure-by-default toggle to set. The one governance-relevant choice is
location, and the module's position is to report whether the residency decision was made here or deferred to run time, rather than to pick for you.
terraform init -backend=false
terraform validate
terraform fmt -checkPin the module at a tag β ?ref=v1.0.0 β never a branch. Everything above is plan-only static analysis; a
human applies from CI.
What terraform validate covers, offline, with no credentials:
- Every
validation {}block in this module β the name pattern and its Resource-ID lookalike check, the anchoredsynapse_workspace_idshape, the three onlocation(non-empty, theAutoResolvenear miss, and not a Resource ID), thecompute_typeenum, thecore_countclosed set, the two ontime_to_live_min(non-negative and whole), thedescriptionnon-empty check, and thetimeoutsduration shapes. - Type conversion of the
timeoutsobject β with the caveat that undeclared keys are discarded silently rather than reported.
What only terraform plan reaches (credentials required):
- That the workspace exists and that its ID parses.
- That the caller's identity holds
Microsoft.Synapse/workspaces/integrationRuntimes/writeon it. - That no runtime of this name already exists β this resource does have an existence check.
- The provider's own region check for
location, and only when it has fetched Azure's location list.
What neither reaches, at any stage:
- Whether the chosen region can supply the requested
core_count. That fails when an activity runs. - Whether any pipeline or data flow selects this runtime. The reference is a string Terraform cannot see.
- Whether the time-to-live is right for the workload. That is a wall-clock and cost measurement, not a check.
Outputs:
id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-data-platform/providers/Microsoft.Synapse/workspaces/syn-platform-prod/integrationRuntimes/ir-dataflow-prod"
name = "ir-dataflow-prod"
synapse_workspace_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-data-platform/providers/Microsoft.Synapse/workspaces/syn-platform-prod"
synapse_workspace_name = "syn-platform-prod"
resource_group_name = "rg-data-platform"
location = "eastus2"
region_is_resolved_at_run_time = false
compute_type = "MemoryOptimized"
core_count = 32
time_to_live_min = 20
cluster_is_torn_down_after_every_activity = false
name_uses_consecutive_dashes = false
force_new_fields = [
"name",
"synapse_workspace_id",
"location",
]
| Symptom | Cause | Fix |
|---|---|---|
| Every data flow takes minutes to start | time_to_live_min is 0, the provider's default, so the cluster is torn down after each activity |
Set a time-to-live. See cluster_is_torn_down_after_every_activity |
| A warm cluster is costing more than expected | It is billed per core-hour for the whole time it stays warm | Lower time_to_live_min or core_count. The two are the whole cost shape |
Raising core_count did not speed up a copy activity |
The compute settings govern data flows only | Expected. See compute_settings_govern_data_flows_only |
core_count must be one of 8, 16, 32, 48, 80, 144 or 272 |
An intermediate value such as 64 was supplied. It is a closed set, not a range | Pick the next step up |
compute_type must be exactly "General", "ComputeOptimized" or "MemoryOptimized" |
A lower-case spelling was used; the provider compares case-sensitively | Use PascalCase |
location must be spelled "AutoResolve" in exactly that casing |
autoresolve was passed, whose acceptance by the provider depends on connectivity |
Use AutoResolve, or a region name in any casing |
| A name with consecutive dashes was accepted here and rejected on the self-hosted runtime | The two resources have different regular expressions and the same error message | Use at least 3 characters and single dashes β legal on both. See the_two_runtime_types_do_not_share_a_name_rule |
| Renaming the runtime broke pipelines, with no plan warning | name is force-new, and pipelines name a runtime as a string Terraform cannot see |
Wire the name output into pipeline definitions rather than retyping it |
| An activity fails at run time with a capacity error | Nothing checks that the chosen region can supply the requested core count | Pin a different region, or lower core_count |
A resource with the ID β¦ already exists |
This resource has a real existence check, and a runtime of that name is already there | terraform import it rather than creating |
Error: Missing required argument: features |
The caller has no provider "azurerm" { features {} } block |
Add one to the root module. This module declares no provider block |
azurerm_synapse_integration_runtime_azureβ the provider resource this module wraps.azurerm_synapse_integration_runtime_self_hostedβ the self-hosted runtime, a different resource.- Integration runtime in Azure Data Factory and Synapse Analytics β Microsoft's platform documentation for the runtime types and what each one is for.
- Data flow performance and tuning β Microsoft's guidance on compute size and time-to-live.
terraform-azurerm-synapse-workspaceβ the parent workspace.terraform-azurerm-synapse-integration-runtime-self-hostedβ the self-hosted runtime.terraform-azurerm-synapse-linked-serviceβ names this runtime so a connection is made through it rather than through Synapse's auto-resolve runtime.terraform-azurerm-synapse-sql-poolandterraform-azurerm-synapse-spark-poolβ the other workloads in the workspace.- This module's
SCOPE.mdβ the cross-module contract.
π "Infrastructure as Code should be standardized, consistent, and secure."