/migrate-nullable-references
Enable nullable reference types in a C# project and systematically resolve all warnings. USE FOR: adopting NRTs in existing codebases, file-by-file or project-wide migration, fixing CS8602/CS8618/CS86xx warnings, annotating APIs for nullability, cleaning up null-forgiving
Claude Code
$ npx -y skills add dotnet/skills --skill migrate-nullable-references --agent claude-code
Codex
$ npx skills add dotnet/skills --skill migrate-nullable-references -a codex -y
Cursor
$ npx skills add dotnet/skills --skill migrate-nullable-references -a cursor -y
Gemini CLI
$ npx skills add dotnet/skills --skill migrate-nullable-references -a gemini-cli -y
GitHub Copilot
$ npx skills add dotnet/skills --skill migrate-nullable-references -a github-copilot -y
OpenCode
$ npx skills add dotnet/skills --skill migrate-nullable-references -a opencode -y
Windsurf
$ npx skills add dotnet/skills --skill migrate-nullable-references -a windsurf -y
SKILL.md
migrate-nullable-references.SKILL.mdname: migrate-nullable-references
description: >
Enable nullable reference types in a C# project and systematically resolve all warnings.
USE FOR: adopting NRTs in existing codebases, file-by-file or project-wide migration,
fixing CS8602/CS8618/CS86xx warnings, annotating APIs for nullability, cleaning up
null-forgiving operators, upgrading dependencies with new nullable annotations.
DO NOT USE FOR: projects already fully migrated with zero warnings (unless auditing
suppressions), fixing a handful of nullable warnings in code that already has NRTs enabled,
suppressing warnings without fixing them, C# 7.3 or earlier projects.
INVOKES: Get-NullableReadiness.ps1 scanner script.
license: MIT
Nullable Reference Migration
Enable C# nullable reference types (NRTs) in an existing codebase and systematically resolve all warnings. The outcome is a project (or solution) with `<Nullable>enable</Nullable>`, zero nullable warnings, and accurately annotated public API surfaces — giving both the compiler and consumers reliable nullability information.
When to Use
- Enabling nullable reference types in an existing C# project or solution
- Systematically resolving CS86xx nullable warnings after enabling the feature
- Annotating a library's public API surface so consumers get accurate nullability information
- Upgrading a dependency that has added nullable annotations and new warnings appear
- Analyzing suppressions in a code base that has already enabled NRTs to determine whether they can be removed
When Not to Use
- The project already has `<Nullable>enable</Nullable>` and zero warnings — the migration is done unless the user wants to re-examine suppressions with a view to removing unnecessary ones (see Step 6)
- The user only wants to suppress warnings without fixing them (recommend against this)
- The code targets C# 7.3 or earlier, which does not support nullable reference types
Inputs
| Input | Required | Description | |-------|----------|-------------| | Project or solution path | Yes | The `.csproj`, `.sln`, or build entry point to migrate | | Migration scope | No | `project-wide` (default) or `file-by-file` — controls the rollout strategy | | Build command | No | How to build the project (e.g., `dotnet build`, `msbuild`, or a repo-specific build script). Detect from the repo if not provided | | Test command | No | How to run tests (e.g., `dotnet test`, or a repo-specific test script). Detect from the repo if not provided |
Workflow
> 🛑 **Zero runtime behavior changes.** NRT migration is strictly a metadata and annotation exercise. The generated IL must not change — no new branches, no new null checks, no changed control flow, no added or removed method calls. The only acceptable changes are nullable annotations (`?`), nullable attributes (`[NotNullWhen]`, etc.), `!` operators (metadata-only), and `#nullable` directives. If you discover a missing runtime null guard or a latent bug during migration, **do not fix it inline**. Instead, offer to insert a `// TODO: Consider adding ArgumentNullException.ThrowIfNull(param)` comment at the site so the user can address it as a separate change. Never mix behavioral fixes into an annotation commit.
> **Commit strategy:** Commit at each logical boundary — after enabling `<Nullable>` (Step 2), after fixing dereference warnings (Step 3), after annotating declarations (Step 4), after applying nullable attributes (Step 5), and after cleaning up suppressions (Step 6). This keeps each commit focused and reviewable, and prevents losing work if a later step reveals a design issue that requires rethinking. For file-by-file migrations, commit each file or batch of related files individually.
Step 1: Evaluate readiness
> **Optional:** Run `scripts/Get-NullableReadiness.ps1 -Path <project-or-solution>` to automate the checks below. The script reports `<Nullable>`, `<LangVersion>`, `<TargetFramework>`, `<WarningsAsErrors>` settings and counts `#nullable disable` directives, `!` operators, and `#pragma warning disable CS86xx` suppressions. Use `-Json` for machine-readable output.
1. Identify how the project is built and tested. Look for build scripts (e.g., `build.cmd`, `build.sh`, `Makefile`), a `.sln` file, or individual `.csproj` files. If the repo uses a custom build script, use it instead of `dotnet build` throughout this workflow. 2. Run `dotnet --version` to confirm the SDK is installed. Nullable reference types (NRTs) require C# 8.0+ (`.NET Core 3.0` / `.NET Standard 2.1` or later). 3. Open the `.csproj` (or `Directory.Build.props` if properties are set at the repo level) and check the `<LangVersion>` and `<TargetFramework>`. If the project multi-targets, note all TFMs.
> **Stop if the language version or target framework is insufficient.** If `<LangVersion>` is below 8.0, or the project targets a framework that defaults to C# 7.x (e.g., `.NET Framework 4.x` without an explicit `<LangVersion>`), NRTs cannot be enabled as-is. Inform the user explicitly: explain what needs to change (set `<LangVersion>8.0</LangVersion>` or higher, or retarget to `.NET Core 3.0+` / `.NET 5+`), and ask whether they want to make that update and continue, or abort the migration. Do not silently proceed or assume the update is acceptable. 4. Check whether `<Nullable>` is already set. If it is set to `enable`, skip to Step 5 to audit remaining warnings. 5. Determine the project type — this shapes annotation priorities throughout the migration:
- **Library**: Focus on public API contracts first. Every `?` on a public parameter or return type is a contract change that consumers depend on. Be precise and conservative.
- **Application (web, console, desktop)**: Focus on null safety at boundaries — deserialization, database queries, user input, external API responses. Internal plumbing can be annotated more liberally.
- **Test project**: Lower priority for annotation precision. Use `!` more freely on test setup and assertions whe
Read more
name: migrate-nullable-references description: > Enable nullable reference types in a C# project and systematically resolve all warnings. USE FOR: adopting NRTs in existing codebases, file-by-file or project-wide migration, fixing CS8602/CS8618/CS86xx warnings, annotating APIs for nullability, cleaning up null-forgiving operators, upgrading dependencies with new nullable annotations. DO NOT USE FOR: projects already fully migrated with zero warnings (unless auditing suppressions), fixing a handful of nullable warnings in code that already has NRTs enabled, suppressing warnings without fixing them, C# 7.3 or earlier projects. INVOKES: Get-NullableReadiness.ps1 scanner script. license: MIT
Nullable Reference Migration
Enable C# nullable reference types (NRTs) in an existing codebase and systematically resolve all warnings. The outcome is a project (or solution) with `<Nullable>enable</Nullable>`, zero nullable warnings, and accurately annotated public API surfaces — giving both the compiler and consumers reliable nullability information.
When to Use
- Enabling nullable reference types in an existing C# project or solution
- Systematically resolving CS86xx nullable warnings after enabling the feature
- Annotating a library's public API surface so consumers get accurate nullability information
- Upgrading a dependency that has added nullable annotations and new warnings appear
- Analyzing suppressions in a code base that has already enabled NRTs to determine whether they can be removed
When Not to Use
- The project already has `<Nullable>enable</Nullable>` and zero warnings — the migration is done unless the user wants to re-examine suppressions with a view to removing unnecessary ones (see Step 6)
- The user only wants to suppress warnings without fixing them (recommend against this)
- The code targets C# 7.3 or earlier, which does not support nullable reference types
Inputs
| Input | Required | Description | |-------|----------|-------------| | Project or solution path | Yes | The `.csproj`, `.sln`, or build entry point to migrate | | Migration scope | No | `project-wide` (default) or `file-by-file` — controls the rollout strategy | | Build command | No | How to build the project (e.g., `dotnet build`, `msbuild`, or a repo-specific build script). Detect from the repo if not provided | | Test command | No | How to run tests (e.g., `dotnet test`, or a repo-specific test script). Detect from the repo if not provided |
Workflow
> 🛑 **Zero runtime behavior changes.** NRT migration is strictly a metadata and annotation exercise. The generated IL must not change — no new branches, no new null checks, no changed control flow, no added or removed method calls. The only acceptable changes are nullable annotations (`?`), nullable attributes (`[NotNullWhen]`, etc.), `!` operators (metadata-only), and `#nullable` directives. If you discover a missing runtime null guard or a latent bug during migration, **do not fix it inline**. Instead, offer to insert a `// TODO: Consider adding ArgumentNullException.ThrowIfNull(param)` comment at the site so the user can address it as a separate change. Never mix behavioral fixes into an annotation commit.
> **Commit strategy:** Commit at each logical boundary — after enabling `<Nullable>` (Step 2), after fixing dereference warnings (Step 3), after annotating declarations (Step 4), after applying nullable attributes (Step 5), and after cleaning up suppressions (Step 6). This keeps each commit focused and reviewable, and prevents losing work if a later step reveals a design issue that requires rethinking. For file-by-file migrations, commit each file or batch of related files individually.
Step 1: Evaluate readiness
> **Optional:** Run `scripts/Get-NullableReadiness.ps1 -Path <project-or-solution>` to automate the checks below. The script reports `<Nullable>`, `<LangVersion>`, `<TargetFramework>`, `<WarningsAsErrors>` settings and counts `#nullable disable` directives, `!` operators, and `#pragma warning disable CS86xx` suppressions. Use `-Json` for machine-readable output.
1. Identify how the project is built and tested. Look for build scripts (e.g., `build.cmd`, `build.sh`, `Makefile`), a `.sln` file, or individual `.csproj` files. If the repo uses a custom build script, use it instead of `dotnet build` throughout this workflow. 2. Run `dotnet --version` to confirm the SDK is installed. Nullable reference types (NRTs) require C# 8.0+ (`.NET Core 3.0` / `.NET Standard 2.1` or later). 3. Open the `.csproj` (or `Directory.Build.props` if properties are set at the repo level) and check the `<LangVersion>` and `<TargetFramework>`. If the project multi-targets, note all TFMs.
> **Stop if the language version or target framework is insufficient.** If `<LangVersion>` is below 8.0, or the project targets a framework that defaults to C# 7.x (e.g., `.NET Framework 4.x` without an explicit `<LangVersion>`), NRTs cannot be enabled as-is. Inform the user explicitly: explain what needs to change (set `<LangVersion>8.0</LangVersion>` or higher, or retarget to `.NET Core 3.0+` / `.NET 5+`), and ask whether they want to make that update and continue, or abort the migration. Do not silently proceed or assume the update is acceptable. 4. Check whether `<Nullable>` is already set. If it is set to `enable`, skip to Step 5 to audit remaining warnings. 5. Determine the project type — this shapes annotation priorities throughout the migration:
- **Library**: Focus on public API contracts first. Every `?` on a public parameter or return type is a contract change that consumers depend on. Be precise and conservative.
- **Application (web, console, desktop)**: Focus on null safety at boundaries — deserialization, database queries, user input, external API responses. Internal plumbing can be annotated more liberally.
- **Test project**: Lower priority for annotation precision. Use `!` more freely on test setup and assertions whe
This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.
Other skills on skills.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about migrate-nullable-references.
- Which coding agents can use migrate-nullable-references?
- migrate-nullable-references installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

