Why does F# configuration binding work locally but fail when deployed to Azure App Service?
0 reputation · 11 Apr 2026, 07:36 UTC
0 reputation · 11 Apr 2026, 07:36 UTC
In local development, an F# console app loads appsettings.json and appsettings.Development.json, binds a section to a record with a single public constructor, and reads the expected values.
When the same app is deployed to Azure App Service, environment variables override the file‑based settings, and the bound record appears with missing or incorrectly typed values, causing the application to fail.
How does the order of configuration providers affect the final bound values when environment variables are present? What steps can be taken to guarantee consistent binding behavior across environments? Is there a way to inspect which provider contributed the final value for each bound property?
35275 reputation · 11 Apr 2026, 13:57 UTC
The most common cause is that Azure App Service runs on a Linux-based container where the file system is case-sensitive, while local Windows development is case-insensitive. If the referenced configuration file name does not match the exact casing on disk, the JSON configuration provider cannot find the file, falls back to environment variables (or defaults), and the bound record receives missing or wrong values.
appsettings.json, appsettings.Development.json or any differently-cased reference resolves correctly.CopyToOutputDirectory setting is missing or set to PreserveNewest, the file may not be copied to the site's wwwroot folder, leading to a FileNotFoundException that is silently ignored when optional:true.AddEnvironmentVariables is called before AddJsonFile, environment values overwrite file values.https://<app-name>.scm.azurewebsites.net/DebugConsole./home/site/wwwroot and confirm appsettings.json (and any environment-specific files) are present with the correct case..fsproj (or .csproj if using SDK-style), set:<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
CopyToPublishDirectory.AddJsonFile (with optional:false for troubleshooting) before AddEnvironmentVariables.let config = ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(sprintf "appsettings.%s.json" env.EnvironmentName, optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build()
Configuration → Application settings.MySection:MyProperty).To confirm whether case sensitivity is the culprit, please verify the underlying OS of your Azure App Service (Windows or Linux). If it is Windows, the issue is likely elsewhere (e.g., missing copy or provider order).
Use comments to ask for clarification. Post a solution as an answer.
6,610 reputation · 11 Apr 2026, 17:17 UTC
While file casing is a common culprit, binding failures in Azure often stem from how hierarchical JSON structures are represented in environment variables. In a local appsettings.json, you might have a nested section like "ServiceSettings": { "ApiKey": "value" }.
When moving to Azure App Service, the environment variable provider does not automatically understand JSON nesting. To ensure the binder maps these to your F# record, you must use the double underscore (__) delimiter in the Azure Portal's Configuration blade:
ServiceSettings:ApiKey (This works in some local providers but can fail in specific Linux environments)ServiceSettings__ApiKeyTo verify this behavior without redeploying, you can simulate the Azure environment locally by setting a system environment variable using the __ syntax and observing if the binder picks it up over the JSON file.