Skip to content

/flags/csharp/dotnet-build-nullable-enable

C# Nullable=enable (dotnet build -p:Nullable): nullable reference type warnings

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 10.0.401updated
tool
C#
command
dotnet build
flag
-p:Nullable=enable|warnings|annotations|disable (<Nullable> in the .csproj)
default
disable in the compiler; enable in the .NET 6+ project templates

<Nullable>enable</Nullable> in a .csproj, or dotnet build -p:Nullable=enable for one build, turns on nullable reference types: string means "never null", string? means "may be null", and the compiler warns when the code can dereference or return a null where it should not (CS8602, CS8618, CS8600 and others). The compiler default is disable, but every project created with dotnet new on .NET 6 or later already contains <Nullable>enable</Nullable>.

Same code, two settings

bash
dotnet new console -n App -o . >/dev/null 2>&1
grep -E '<Nullable>' App.csproj
cat > Program.cs <<'EOF'
string? name = args.Length > 0 ? args[0] : null;
Console.WriteLine(name.Length);
class Person { public string Name { get; set; } }
EOF
build() { dotnet build --no-incremental "$@" 2>&1 | grep -oE "(warning|error) CS[0-9]+[^[]*" | sort -u; echo "exit: ${PIPESTATUS[0]}"; }
echo "== Nullable=enable (template default)"
build
echo "== -p:Nullable=disable"
build -p:Nullable=disable
echo "== -p:Nullable=warnings"
build -p:Nullable=warnings
echo "== -p:Nullable=annotations"
build -p:Nullable=annotations

Output

    <Nullable>enable</Nullable>
== Nullable=enable (template default)
warning CS8602: Dereference of a possibly null reference.
warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
exit: 0
== -p:Nullable=disable
warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
exit: 0
== -p:Nullable=warnings
warning CS8602: Dereference of a possibly null reference.
warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
exit: 0
== -p:Nullable=annotations
exit: 0

With enable the compiler reports the possible null dereference (CS8602) and the non-nullable property that is never set (CS8618). With disable those warnings disappear, and the string? annotation itself becomes warning CS8632 because annotations are not allowed in a disabled context. annotations accepts the syntax but produces no null-safety warnings. All are warnings: the build succeeds unless you treat warnings as errors.

--no-incremental matters when you only change a property on the command line: an incremental build may decide that nothing changed and skip the compiler, so the new setting seems to have no effect.

The four values

ValueAnnotations (string?)WarningsTypical use
enableallowed, meaningfulyesNew code; default of the .NET templates
warningsnot allowed (CS8632)yes, for dereferences of values known to be nullFirst migration step for old code
annotationsallowednoLibraries that publish annotations before fixing every warning
disablenot allowed (CS8632)noCompiler default; legacy projects

Where to set it

App.csproj
<PropertyGroup>
  <Nullable>enable</Nullable>
  <!-- make the most important nullable warnings fatal -->
  <WarningsAsErrors>$(WarningsAsErrors);CS8602;CS8618</WarningsAsErrors>
</PropertyGroup>
csharp
#nullable enable      // from here on in this file
#nullable disable     // switch off again
#nullable restore     // back to the project setting

Putting the property in Directory.Build.props applies it to every project in the repository. The command-line form dotnet build -p:Nullable=enable is handy for a quick check of how many warnings a legacy project would get.

Migration tips

  • Start with warnings, fix what it reports, then switch to enable and add ? where null is really allowed.
  • Fix CS8618 with required members, constructor parameters, or initial values, not with = null!, which only silences the warning.
  • Use ArgumentNullException.ThrowIfNull(arg) at public API boundaries; the annotation does not stop callers with nullable disabled from passing null.
  • Generated code (*.g.cs, *.designer.cs) is treated as disabled unless the file opts in with #nullable enable.

FAQ

Does Nullable=enable change how my program runs?

No. Nullable reference types are a compile-time analysis: the compiler emits warnings and metadata, but the generated code does not check for null at run time. A null can still arrive and cause a NullReferenceException; the warnings show where that can happen.

How do I enable nullable checks for one file only?

Put #nullable enable at the top of the file (and #nullable restore or disable where you want to stop). This is the usual way to migrate a large project file by file before switching the project setting.

Why do I get CS8632 about the annotation for nullable reference types?

The code uses string? or another nullable reference annotation while the nullable context is disabled. Enable it with <Nullable>enable</Nullable> or #nullable enable, or remove the question mark.

Sources