Trimming options
The following MSBuild properties and items influence the behavior of trimmed self-contained deployments. Some of the options mention ILLink
, which is the name of the underlying tool that implements trimming. For more information about the underlying tool, see the Trimmer documentation.
Trimming with PublishTrimmed
was introduced in .NET Core 3.0. The other options are available only in .NET 5 and later versions.
Enable trimming
<PublishTrimmed>true</PublishTrimmed>
Enable trimming during publish. This setting also turns off trim-incompatible features and enables trim analysis during build. In .NET 8 and later apps, this setting also enables the configuration binding and request delegate source generators.
Note
If you specify trimming as enabled from the command line, your debugging experience will differ and you might encounter additional bugs in the final product.
Place this setting in the project file to ensure that the setting applies during dotnet build
, not just dotnet publish
.
This setting enables trimming and trims all assemblies by default. In .NET 6, only assemblies that opted-in to trimming via [AssemblyMetadata("IsTrimmable", "True")]
(added in projects that set <IsTrimmable>true</IsTrimmable>
) were trimmed by default. You can return to the previous behavior by using <TrimMode>partial</TrimMode>
.
This setting trims any assemblies that have been configured for trimming. With Microsoft.NET.Sdk
in .NET 6, this includes any assemblies with [AssemblyMetadata("IsTrimmable", "True")]
, which is the case for the .NET runtime assemblies. In .NET 5, assemblies from the netcoreapp runtime pack are configured for trimming via <IsTrimmable>
MSBuild metadata. Other SDKs might define different defaults.
This setting also enables the trim-compatibility Roslyn analyzer and disables features that are incompatible with trimming.
Trimming granularity
Use the TrimMode
property to set the trimming granularity to either partial
or full
. The default setting for console apps (and, starting in .NET 8, Web SDK apps) is full
:
<TrimMode>full</TrimMode>
To only trim assemblies that have opted-in to trimming, set the property to partial
:
<TrimMode>partial</TrimMode>
If you change the trim mode to partial
, you can opt-in individual assemblies to trimming by using a <TrimmableAssembly>
MSBuild item.
<ItemGroup>
<TrimmableAssembly Include="MyAssembly" />
</ItemGroup>
This is equivalent to setting [AssemblyMetadata("IsTrimmable", "True")]
when building the assembly.
The following granularity settings control how aggressively unused IL is discarded. This can be set as a property affecting all trimmer input assemblies, or as metadata on an individual assembly, which overrides the property setting.
<TrimMode>link</TrimMode>
Enable member-level trimming, which removes unused members from types. This is the default in .NET 6+.
<TrimMode>copyused</TrimMode>
Enable assembly-level trimming, which keeps an entire assembly if any part of it is used (in a statically understood way).
Assemblies with <IsTrimmable>true</IsTrimmable>
metadata but no explicit TrimMode
will use the global TrimMode
. The default TrimMode
for Microsoft.NET.Sdk
is link
in .NET 6+, and copyused
in previous versions.
Trim additional assemblies
In .NET 6+, PublishTrimmed
trims assemblies with the following assembly-level attribute:
[AssemblyMetadata("IsTrimmable", "True")]
The framework libraries have this attribute. In .NET 6+, you can also opt in to trimming for a library without this attribute, specifying the assembly by name (without the .dll
extension).
Trimming settings for individual assemblies
When publishing a trimmed app, the SDK computes an ItemGroup
called ManagedAssemblyToLink
that represents the set of files to be processed for trimming. ManagedAssemblyToLink
might have metadata that controls the trimming behavior per assembly. To set this metadata, create a target that runs before the built-in PrepareForILLink
target. The following example shows how to enable trimming of MyAssembly
.
<Target Name="ConfigureTrimming"
BeforeTargets="PrepareForILLink">
<ItemGroup>
<ManagedAssemblyToLink Condition="'%(Filename)' == 'MyAssembly'">
<IsTrimmable>true</IsTrimmable>
</ManagedAssemblyToLink>
</ItemGroup>
</Target>
You can also use this target to override the trimming behavior specified by the library author, by setting <IsTrimmable>false</IsTrimmable>
for an assembly with [AssemblyMetadata("IsTrimmable", "True"])
.
Do not add or remove items from ManagedAssemblyToLink
, because the SDK computes this set during publish and expects it not to change. The supported metadata is:
<IsTrimmable>true</IsTrimmable>
Control whether the given assembly is trimmed.
<TrimMode>copyused</TrimMode>
or<TrimMode>link</TrimMode>
Control the trimming granularity of this assembly. This metadata takes precedence over the global
TrimMode
. SettingTrimMode
on an assembly implies<IsTrimmable>true</IsTrimmable>
.<TrimmerSingleWarn>True</TrimmerSingleWarn>
Control whether to show single warnings for this assembly.
Root assemblies
If an assembly is not trimmed, it's considered "rooted", which means that it and all of its statically understood dependencies will be kept. Additional assemblies can be "rooted" by name (without the .dll
extension):
<ItemGroup>
<TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>
Root descriptors
Another way to specify roots for analysis is using an XML file that uses the trimmer descriptor format. This lets you root specific members instead of a whole assembly.
<ItemGroup>
<TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>
For example, MyRoots.xml
might root a specific method that's dynamically accessed by the application:
<linker>
<assembly fullname="MyAssembly">
<type fullname="MyAssembly.MyClass">
<method name="DynamicallyAccessedMethod" />
</type>
</assembly>
</linker>
Analysis warnings
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
Enable trim analysis warnings.
Trimming removes IL that's not statically reachable. Apps that use reflection or other patterns that create dynamic dependencies might be broken by trimming. To warn about such patterns, set <SuppressTrimAnalysisWarnings>
to false
. This setting will surface warnings about the entire app, including your own code, library code, and framework code.
Roslyn analyzer
Setting PublishTrimmed
in .NET 6+ also enables a Roslyn analyzer that shows a limited set of analysis warnings. You can also enable or disable the analyzer independently of PublishTrimmed
.
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
Enable a Roslyn analyzer for a subset of trim analysis warnings.
Suppress warnings
You can suppress individual warning codes using the usual MSBuild properties respected by the toolchain, including NoWarn
, WarningsAsErrors
, WarningsNotAsErrors
, and TreatWarningsAsErrors
. There's an additional option that controls the ILLink warn-as-error behavior independently:
<ILLinkTreatWarningsAsErrors>false</ILLinkTreatWarningsAsErrors>
Don't treat ILLink warnings as errors. This might be useful to avoid turning trim analysis warnings into errors when treating compiler warnings as errors globally.
Show detailed warnings
In .NET 6+, trim analysis produces at most one warning for each assembly that comes from a PackageReference
, indicating that the assembly's internals are not compatible with trimming. You can also show individual warnings for all assemblies:
<TrimmerSingleWarn>false</TrimmerSingleWarn>
Show all detailed warnings, instead of collapsing them to a single warning per assembly.
Remove symbols
Symbols are usually trimmed to match the trimmed assemblies. You can also remove all symbols:
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
Remove symbols from the trimmed application, including embedded PDBs and separate PDB files. This applies to both the application code and any dependencies that come with symbols.
The SDK also makes it possible to disable debugger support using the property DebuggerSupport
. When debugger support is disabled, trimming removes symbols automatically (TrimmerRemoveSymbols
will default to true).
Trimming framework library features
Several feature areas of the framework libraries come with trimmer directives that make it possible to remove the code for disabled features.
<AutoreleasePoolSupport>false</AutoreleasePoolSupport>
(default)Remove code that creates autorelease pools on supported platforms. See AutoreleasePool for managed threads. This is the default for the .NET SDK.
<DebuggerSupport>false</DebuggerSupport>
Remove code that enables better debugging experiences. This setting also removes symbols.
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
Remove BinaryFormatter serialization support. For more information, see BinaryFormatter serialization methods are obsolete.
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
Remove insecure UTF-7 encoding code. For more information, see UTF-7 code paths are obsolete.
<EventSourceSupport>false</EventSourceSupport>
Remove EventSource related code or logic.
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
Remove code related to diagnostics support for System.Net.Http.
<InvariantGlobalization>true</InvariantGlobalization>
Remove globalization-specific code and data. For more information, see Invariant mode.
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
Remove metadata update-specific logic related to hot reload.
<MetricsSupport>false</MetricsSupport>
Removes support for System.Diagnostics.Metrics instrumentation.
<StackTraceSupport>false</StackTraceSupport>
(.NET 8+)Remove support for generating stack traces (for example, Environment.StackTrace, or Exception.ToString) by the runtime. The amount of information that will be removed from stack trace strings may depend on other deployment options. This option does not affect stack traces generated by debuggers.
<UseNativeHttpHandler>true</UseNativeHttpHandler>
Use the default platform implementation of HttpMessageHandler for Android/iOS and remove the managed implementation.
<UseSystemResourceKeys>true</UseSystemResourceKeys>
Strip exception messages for
System.*
assemblies. When an exception is thrown from aSystem.*
assembly, the message is a simplified resource ID instead of the full message.
These properties cause the related code to be trimmed and also disable features via the runtimeconfig file. For more information about these properties, including the corresponding runtimeconfig options, see feature switches. Some SDKs might have default values for these properties.
Framework features disabled when trimming
The following features are incompatible with trimming because they require code that's not statically referenced. These features are disabled by default in trimmed apps.
Warning
Enable these features at your own risk. They are likely to break trimmed apps without extra work to preserve the dynamically referenced code.
<BuiltInComInteropSupport>
Built-in COM support is disabled.
<CustomResourceTypesSupport>
Use of custom resource types isn't supported. ResourceManager code paths that use reflection for custom resource types are trimmed.
<EnableCppCLIHostActivation>
C++/CLI host activation is disabled.
<EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization>
DesigntimeLicenseContextSerializer use of
BinaryFormatter
serialization is disabled.<StartupHookSupport>
Running code before
Main
withDOTNET_STARTUP_HOOKS
isn't supported. For more information, see host startup hook.