Global Using Directives in C

Global using directives, introduced in C# 10 and .NET 6, allow developers to define namespace imports that apply across an entire project rather than a single file. This article explains how global using directives work, demonstrates their syntax, and illustrates how they significantly reduce boilerplate code to keep C# files clean and maintainable.

What Are Global Using Directives?

In traditional C#, every source file begins with a list of using directives declaring the namespaces required for that specific file. Because most files in a modern application share standard namespaces—such as System, System.Collections.Generic, and System.Linq—developers routinely duplicate the same dozen lines of boilerplate code in dozens or hundreds of files.

A global using directive solves this by prepending the global keyword to a standard using statement. When you declare a namespace globally, the compiler automatically includes that namespace in every C# file compiled within that project.

global using System;
global using System.Collections.Generic;
global using System.Linq;

How Global Usings Clean Up Code

By centralizing common imports, individual code files are relieved of redundant headers. A typical file that previously required ten lines of import declarations can now start directly with its namespace declaration or class definition. This declutters your codebase, speeds up navigation, and allows developers to focus immediately on business logic rather than import management.

Global directives also support aliases and static imports, making them versatile for cross-cutting framework dependencies:

// Global static import
global using static System.Math;

// Global namespace alias
global using JsonConverter = System.Text.Json.Serialization.JsonConverterAttribute;

While you can technically place global using statements in any .cs file in your project, scattering them causes confusion. The widely accepted best practice is to consolidate all global usings into a single, dedicated file at the root of the project, typically named Usings.cs or GlobalUsings.cs.

Example GlobalUsings.cs:

global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Net.Http;
global using System.Threading.Tasks;
global using Microsoft.Extensions.Logging;

With this single file in place, no other file in the project needs to import these namespaces.

Project File Integration and Implicit Usings

Global usings can also be managed directly in the .csproj file using the <Using> MSBuild item:

<ItemGroup>
  <Using Include="System.Text.Json" />
  <Using Include="MyProject.Common.Services" />
</ItemGroup>

Furthermore, .NET 6 and later feature Implicit Usings, enabled by default in new project templates via <ImplicitUsings>enable</ImplicitUsings> in the .csproj file. When enabled, the SDK automatically generates a hidden set of global usings based on the project type (for example, standard core namespaces for console apps, or ASP.NET Core namespaces for web apps).

To remove an implicit namespace that causes conflicts, you can use the Remove attribute in the project file:

<ItemGroup>
  <Using Remove="System.Net.Http" />
</ItemGroup>

Best Practices

  • Keep It Relevant: Only apply global using to namespaces that are genuinely needed in the majority of files across the project.
  • Avoid Collisions: Be cautious with namespaces that share identical class names (e.g., System.Diagnostics.Debug vs. other logging abstractions) to avoid ambiguity errors across the build.
  • Standardize Placement: Use a single GlobalUsings.cs file per project to ensure team members can easily locate and maintain the project's baseline imports.