Azure Functions provide a powerful serverless compute option, and application settings heavily influence their behavior. These settings control the function’s runtime, build, deployment strategies, and other platform features. Additionally, they serve as a conduit for infrastructure outputs from dependent Azure services that are provisioned using Terraform. This article outlines how to merge infrastructure-specific configuration with application-specific settings in a clean and maintainable way.

Defining the Application Settings

Application-specific settings dictate the function’s execution environment, including aspects such as build strategies, worker runtime, and operational toggles. These settings are generally constant strings because they won’t change unless the fundamental nature of the function app’s deployment or platform architecture changes. The following Terraform locals block defines these settings:

locals {
  azure_functions_settings = {
    "ENABLE_ORYX_BUILD"                                          = "true"
    "BUILD_FLAGS"                                                = "UseExpressBuild"
    "XDG_CACHE_HOME"                                             = "/tmp/.cache"
    "FUNCTIONS_WORKER_RUNTIME"                                   = "python"
    "SCM_DO_BUILD_DURING_DEPLOYMENT"                             = "true"
    "AzureWebJobs.quality_assessment_eventgrid_trigger.Disabled" = "1"
    "AzureWebJobs.quality_assessment_sbt.Disabled"               = "0"
  }
}

Defining the Infrastructure Settings

Infrastructure settings contain values that are dynamically derived from Azure resources provisioned through Terraform. These settings may either be created by Terraform or referenced using Terraform data sources, ensuring they reflect the current infrastructure state. Examples include service connection strings, endpoints, and identity configurations:

locals {
  application_settings = {
    "AzureWebJobs.function_feedback.Disabled"       = "1"
    "AZURE_OPEN_AI__DEPLOYMENT_NAME"                = "gpt-4o"
    "AZURE_OPEN_AI__ENDPOINT"                       = var.openai_endpoint
    "FUNCTION_MANAGED_IDENTITY"                     = azurerm_user_assigned_identity.function.client_id
    "ServiceBusConnection__fullyQualifiedNamespace" = "${data.azurerm_servicebus_namespace.main.name}.servicebus.windows.net"
  }
}

Merging the Settings

To ensure both application-specific and infrastructure-specific configurations are applied to the Azure Function, we merge these two settings blocks into a single local variable:

locals {

  all_settings = merge(local.application_settings, local.azure_functions_settings)
}

The merge function combines the key-value pairs from both local maps, ensuring that all required settings are consolidated into a single structure. This logical separation of settings improves readability and maintainability by grouping similar settings together rather than having one large, disorganized block of key-value pairs. It also allows developers to add targeted comments, providing clear guidance for future authors and making it easier to identify related settings that might be relevant for future modifications.

Applying the Merged Settings to the Function App

The final step is to apply the merged settings to the Azure Linux Function App resource using the app_settingsproperty:

resource "azurerm_linux_function_app" "main" {

  // Other Stuff

  app_settings = local.all_settings

}

Conclusion

By separating application-specific and infrastructure-specific settings and merging them, we achieve a clear, maintainable, and scalable configuration strategy for Azure Function Apps. This approach allows flexibility while ensuring infrastructure outputs dynamically update function app settings without additional manual intervention. Recognizing which settings should be constant strings versus those that should be dynamically sourced ensures a balance between stability and adaptability in your function app’s configuration. Furthermore, this separation enhances code readability and maintainability, making it easier for future developers to understand and modify settings as needed.