# Microsoft.Unity.Analyzers: Roslyn diagnostics that understand Unity

> Microsoft.Unity.Analyzers is a Roslyn analyzer package that teaches Visual Studio about Unity projects, adding Unity specific diagnostics and suppressing the general C# ones that do not apply. It ships in the box with the Unity workload, and the interesting part of adopting it is the duplicate diagnostics you get if you also install the extension.

**microsoft/Microsoft.Unity.Analyzers** — Roslyn analyzers for Unity game developers

- Repository: https://github.com/microsoft/Microsoft.Unity.Analyzers
- Stars: 817 · Forks: 88
- Language: C#
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/microsoft-microsoft-unity-analyzers

## Analyzers that know a game project is not a class library

Microsoft.Unity.Analyzers is a set of Roslyn analyzers for Unity game developers. The project's own summary is the clearest description of the purpose: it provides Visual Studio with a better understanding of Unity projects by adding Unity-specific diagnostics, or by removing general C# diagnostics that do not apply to Unity projects.

Both halves of that sentence matter. An analyzer package that only adds rules is a lint tool, and a package that only removes rules is a suppression list. This one does both, and the removal half is what makes it different from every other Unity linting extension you can install.

The general C# diagnostics it removes are the ones a game project cannot satisfy. A large part of the .NET ecosystem's guidance is written for servers and libraries: advice about allocation patterns, about lifetime, about patterns that make sense when a process is long lived and a request arrives at a time. Unity's player loop, its object lifetime and its per-frame update cycle make some of that advice noise, and a developer who suppresses those warnings by hand in every project is doing work the tool should do.

The language is C#, the licence is MIT, and the repository carries a doc directory whose index.md holds the list of analyzers and suppressors defined in the project. That list is the reference to read before adopting it, because the exact set of diagnostics is the thing that determines whether the package helps your codebase or merely adds to your warning list.

## DiagnosticSuppressor is how the suppression actually works

The project states that it uses the DiagnosticSuppressor API to conditionally suppress reported compiler and analyzer diagnostics.

That sentence explains the whole design in technical terms. A DiagnosticSuppressor is not a rule engine: it does not report problems of its own in the way an analyzer does. It observes diagnostics that something else already reported, the compiler or another analyzer, and decides whether to suppress them given the context of the code.

The word conditionally is the important part. A suppressor is not a global mute. It looks at where the diagnostic was reported, in what kind of member, in what kind of type, and decides whether the rule applies to that context. That is why the package can remove diagnostics that do not apply to Unity projects without silencing them everywhere, and why the same codebase can contain Unity-specific code and ordinary library code with different rules applied to each.

It also explains the division of labour inside the package. The analyzers add the Unity-specific diagnostics, the ones about patterns that only make sense in a game engine. The suppressors handle the removals. The project's own tooling for adding new rules reflects that split: the scaffolding command creates a suppressor instead of an analyzer when the name you pass contains the word suppressor, and otherwise creates a regular analyzer and codefix.

For a Unity developer the practical consequence is that the package is not something you configure per project with a rule set file. It is a fixed behaviour, and your lever is the analyzer list, not a settings file.

## In Visual Studio it already ships with the Unity workload

The release section is short and it changes the installation question entirely.

For Visual Studio these analyzers ship in the box, in the Game development with Unity workload. You do not install them from NuGet to use them in Visual Studio.

For Visual Studio Code, the documentation points you at the official Unity extension instead. The repository links that extension from the marketplace as VisualStudioToolsForUnity.vstuc, and the framing is that the extension is the route for VS Code rather than the analyzer package.

The NuGet package exists for two other audiences. It is there for people building class libraries for Unity, where the library is compiled outside the editor, and for other advanced usages. So there are three distinct consumption paths and they are not interchangeable: the in-box workload for Unity game development in Visual Studio, the official extension for VS Code, and the NuGet package for library authors and advanced scenarios.

The distinction matters for the reason that follows, because the in-box path applies the analyzers to everything open in the IDE, while the NuGet path is referenced per project.

The project is at version 1.28.0, released on 2026-09-29, with 1.27.0 in August 2026 and 1.26.0 in February 2026, and the last push to the repository was on 2026-10-16. That is a steady release cadence for a diagnostics package, which matters because the set of general C# diagnostics changes with each .NET release and has to be tracked.

## The duplicate diagnostics trap and the script that fixes it

There is a specific, well documented failure mode here, and if you install the extension without reading this section you will hit it.

Starting with Visual Studio Tools for Unity 4.3.2.0, the analyzers and suppressors from this project ship and are automatically included in all projects generated by Unity, using an Analyzer Include directive. The downside, in the project's words, is that when you try to debug your own solution you find yourself with duplicated diagnostics, because Visual Studio loads both the project-local analyzer that is released and included automatically through that directive, and the VSIX extension you deployed, which applies analyzers and suppressors to all projects in the IDE.

Two delivery mechanisms, one set of rules, one editor, and every diagnostic reported twice.

The documented fix is a small script in an Editor folder of your Unity project, which post processes the generated project file and disables the analyzers loaded through the directive:

```csharp
using UnityEditor;
using System.Text.RegularExpressions;

public class DisableLocalAnalyzersPostProcessor : AssetPostprocessor
{
	public static string OnGeneratedCSProject(string path, string content)
	{
		return Regex.Replace(content, "(\\<Analyzer)\\s+(Include=\".*Microsoft\\.Unity\\.Analyzers\\.dll\")", "$1 Condition=\"false\" $2");
	}
}
```

The regex rewrites the Analyzer element to carry a Condition of false, which disables the local analyzer reference. The reason it is a post processor rather than a hand edit is stated in the documentation: it keeps a workflow that is compatible with Unity regenerating the project files on every asset change, so the change survives the next regeneration instead of being overwritten.

This is the single most useful piece of the documentation for anybody evaluating the package, because it tells you that the IDE integration is not frictionless. Two ways to load the same rules exist, and the package documents the collision and the fix.

## Building it needs .NET 10, Visual Studio 2026 and Unity

Building and testing this project has a prerequisite list that is worth reading before you clone it.

For building and testing you need .NET 10 and Visual Studio 2026, or Visual Studio Code 1.92 and newer. On Windows you also need the Visual Studio extension development workload installed, because the build produces a VSIX that you use and debug inside Visual Studio. And for unit testing, Unity has to be installed, with the recommendation to use the latest LTS version.

The Unity requirement is the one that changes the shape of a contributor's setup. This is not a package you can build with the .NET SDK alone; the tests exercise diagnostics against real Unity project structures, so the engine has to be present.

The build itself is one command:

```bash
dotnet build .\src\Microsoft.Unity.Analyzers.slnx
```

and the tests are run through Microsoft Testing Platform, with failed tests retried up to three times:

```bash
dotnet .\src\Microsoft.Unity.Analyzers.Tests\bin\Debug\net10.0\Microsoft.Unity.Analyzers.Tests.dll --retry-failed-tests 3
```

The retry flag is a small thing with a reason behind it. Unity project generation and analyzer behaviour can be sensitive to ordering and to the state of a generated project, so a test that fails once may pass on a retry. A suite that reruns failures three times is a suite designed around that reality rather than one that assumes determinism.

The solution file is a .slnx, the newer XML based format, and the documentation says you can open it in your favourite IDE to work on the analyzers and run or debug the tests.

## Debugging an analyzer against a real Unity project

The documentation is explicit that running and debugging the tests is the easiest way to get started, but that sometimes you want to work on a real-life Unity project. The Visual Studio path is spelled out.

You open the Microsoft.Unity.Analyzers.Vsix.slnx solution, make sure that Microsoft.Unity.Analyzers.Vsix is set as the startup project, and then hit play, described as Current Instance, which starts debugging an experimental instance of Visual Studio. You load any Unity project in that experimental instance and put breakpoints in the Microsoft.Unity.Analyzers project.

That workflow is worth understanding because it explains why the VSIX project exists at all. The analyzers run inside the IDE, so debugging them means running the IDE. The experimental instance means you are not debugging inside the Visual Studio you are using to write code, which would otherwise mean restarting the editor on every breakpoint hit.

The repository structure supports the same idea. There is a src directory holding the solution files, a doc directory with the analyzer list, a .husky directory for git hooks, a .config directory and the usual GitHub and contributor files including CONTRIBUTING.md, SECURITY.md and a CODE_OF_CONDUCT.md. The project welcomes contributions and suggestions, and points to the guidelines in CONTRIBUTING.md.

## Scaffolding a new analyzer in one command

The tooling for adding rules is the part of the repository that makes it a real contribution target rather than a fixed set of warnings.

To create a new analyzer you run a command in the repository:

```bash
dotnet run --project .\src\new-analyzer
```

This automatically creates the source files for the analyzer, the associated tests, and the resource entries, which is the part that is tedious by hand: every analyzer needs a diagnostic descriptor with a message, a category, a severity and an id, and the tests need a fixture project to run against.

The tool reads the name you give it. If the name contains the word suppressor, it creates a suppressor instead, and by default it creates a regular analyzer and a codefix. The examples in the documentation are explicit about the naming that results: running it with Custom produces CustomAnalyzer, CustomCodeFix and CustomTests classes, and running it with CustomSuppressor produces CustomSuppressor and CustomSuppressorTests classes.

That default of creating a codefix alongside an analyzer is a design choice worth noticing. A diagnostic that only reports leaves the developer with a problem and no route forward. Generating the fix alongside it means a new rule arrives with a solution attached, which is why the package can be extended by people outside Microsoft without them having to write the plumbing.

The suggestion path for new rules is also documented and simple: if you have an idea for a best practice for Unity developers to follow, open an issue with the description, using the feature request template in the repository.

## Conclusion

Microsoft.Unity.Analyzers suits a Unity team that writes C# and wants the editor to stop reporting general language diagnostics that are wrong for a game project, without maintaining a private analyzer set. It is the wrong choice if you need to suppress a specific warning that only your project triggers, since the shipped set is fixed and the suppressor model is about Unity specifics, and it is the wrong choice if you are on VS Code and expect the package to work there, because on VS Code the route is the official Unity extension. Verify three things before you enable it: that you are not loading the analyzers twice, which the documentation shows produces duplicated diagnostics, that your Visual Studio or VS Code version meets the stated prerequisites, and that the specific diagnostics you care about are actually in the list the project publishes.

## FAQ

### What does Microsoft.Unity.Analyzers do for a Unity project?

It gives Visual Studio a better understanding of Unity projects by adding Unity-specific diagnostics and by removing the general C# diagnostics that do not apply to Unity projects. The project uses the DiagnosticSuppressor API to conditionally suppress reported compiler and analyzer diagnostics.

### How do I get the analyzers in Visual Studio and in VS Code?

For Visual Studio they ship in the box with the Game development with Unity workload. For Visual Studio Code the project points at the official Unity extension instead, and the NuGet package is for people building class libraries for Unity and other advanced usages.

### Why am I seeing every diagnostic twice in Visual Studio?

Since Visual Studio Tools for Unity 4.3.2.0 the analyzers are included automatically in Unity generated projects through an Analyzer Include directive, and the VSIX extension you deployed also applies them to all projects in the IDE. The documentation provides an Editor script that rewrites the generated project file to disable the local analyzer references.

### What do I need to build and test Microsoft.Unity.Analyzers?

You need .NET 10 with Visual Studio 2026, or Visual Studio Code 1.92 and newer, the Visual Studio extension development workload on Windows to build the VSIX, and Unity installed for the unit tests, with the latest LTS recommended.

### How do I create a new analyzer in this project?

Run dotnet run --project .\src\new-analyzer, optionally with a name such as Custom or CustomSuppressor. The tool creates the analyzer source, the tests and the resource entries, and it creates a suppressor instead when the name contains the word suppressor.

### Where can I see the list of analyzers and suppressors?

The repository points to the list of analyzers and suppressors defined in the project in the doc/index.md file. New rule ideas are welcome through the issue tracker using the feature request template.

## Sources

- [Issues](https://github.com/microsoft/Microsoft.Unity.Analyzers/issues)
- [License: MIT](https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/LICENSE)
- [microsoft/Microsoft.Unity.Analyzers on GitHub](https://github.com/microsoft/Microsoft.Unity.Analyzers)
- [README](https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/README.md)
- [Releases](https://github.com/microsoft/Microsoft.Unity.Analyzers/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/microsoft-microsoft-unity-analyzers
