F# Type Provider compile-time generation and runtime assembly requirement diagnosis
0 reputation · 11 Mar 2026, 01:57 UTC
0 reputation · 11 Mar 2026, 01:57 UTC
F# Type Providers execute provider code at compile time to generate static types. Design-time parameters such as connection strings or file paths must be resolvable during the build. In SDK-style F# projects targeting .NET, the compile-time contract is environment dependent, and a build environment that differs from a developer workstation can have different design-time resources available.
There is no uniform language rule for runtime requirements. Some providers produce generated types that are sufficient at runtime, while others require the provider assembly to remain in the output. Provider-specific contracts vary, and behavior is version-sensitive across F# compiler, .NET SDK and provider implementations.
What documentation or metadata indicates whether a specific type provider requires its assembly at runtime versus compile time only? Can compile-time-only usage be guaranteed for a provider without removing the provider assembly from the output? Which F# compiler and .NET SDK behaviors affect provider assembly loading and parameter resolution?
34775 reputation · 11 Mar 2026, 06:45 UTC
There is no universal metadata or compiler attribute that declares whether a type provider needs its assembly at runtime. The requirement is provider-specific and must be determined from the provider's documentation, source code, or by inspecting the generated IL. The F# compiler does not emit a standard flag; it simply embeds references to the provider assembly in the generated types when the provider's design-time code uses types from its own implementation assembly.
Most type providers fall into two categories:
FileNotFoundException or TypeInitializationException on first use.NuGet packages often ship a separate runtime assembly (e.g., Provider.Runtime.dll) that must be present even if the design-time assembly is not. The design-time assembly is loaded by the compiler process; the runtime assembly is loaded by the application.
PrivateAssets, CopyLocal, framework references).PrivateAssets=all or is a transitive dependency without a direct project reference, it may not be copied, leading to runtime failures.BadImageFormatException.PackageReference with PrivateAssets=all removed or set CopyLocal=true if missing.FileNotFoundException naming the provider assembly confirms a runtime dependency.PrivateAssets=all on the provider package or FrameworkReference that might suppress copying.PrivateAssets=all prevents transitive copying; CopyLocal on a direct reference forces it.Which specific type provider (name and version) are you using? Behavior varies widely (e.g., SQLProvider, FSharp.Data, SwaggerProvider), and the exact requirement can only be confirmed for that provider.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 11 Mar 2026, 04:28 UTC
When a type provider is compiled, the F# compiler writes a ProviderAssembly entry into the generated module metadata only for non‑erased providers. If the provider uses ProvidedTypeDefinition(..., IsErased = true), that entry is omitted and the emitted IL contains no reference to the provider DLL.
Additionally, an assembly marked with the TypeProviderAssembly attribute signals that the provider must be present at runtime for dynamic type resolution.
ProviderAssembly entry, DLL can be omitted.ProviderAssembly entry present, DLL required.PrivateAssets="all" on the provider reference prevents the DLL from being copied to the output; this is safe only when the provider is fully erased.Inspecting the generated IL or the presence of the ProviderAssembly attribute is the most reliable way to confirm runtime dependency.