website/src/docs/hotchocolate/v16/building-a-schema/non-null.md
By default, every GraphQL field can return either its declared type or null. The non-null modifier (!) tells clients that a field will never be null. If a resolver returns null for a non-null field, the execution engine raises an error rather than sending unexpected null values to clients.
type User {
name: String!
bio: String
}
In this schema, name always has a value. The bio field may be null.
Hot Chocolate infers nullability from your C# types. When nullable reference types (NRT) are enabled in your project, the mapping is straightforward.
Value types are non-null by default. Use ? to make them nullable.
| C# type | GraphQL type |
|---|---|
int | Int! |
int? | Int |
bool | Boolean! |
bool? | Boolean |
With NRT enabled (recommended), non-nullable references map to non-null GraphQL types.
| C# type | GraphQL type |
|---|---|
string | String! |
string? | String |
User | User! |
User? | User |
Without NRT, all reference types are nullable by default. Hot Chocolate cannot distinguish string from string? because the compiler treats them identically.
| C# type | GraphQL type |
|---|---|
string | String |
User | User |
We strongly recommend enabling NRT. It provides accurate schema nullability without extra attributes and catches null-related bugs at compile time.
Add the following to your .csproj file to enable NRT across the project:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
You can also enable it per file with #nullable enable at the top of the file.
When you need to override the inferred nullability, use attributes or the descriptor API.
<ExampleTabs> <Implementation>// Types/Book.cs
public class Book
{
[GraphQLNonNullType]
public string Title { get; set; }
public string? Author { get; set; }
}
[GraphQLNonNullType] forces the field to be non-null in the schema regardless of the C# nullability.
// Types/BookType.cs
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor
.Field(f => f.Title)
.Type<NonNullType<StringType>>();
descriptor
.Field(f => f.Author)
.Type<StringType>();
}
}
Lists have two layers of nullability: the list itself and its items. With NRT enabled:
| C# type | GraphQL type |
|---|---|
List<string> | [String!]! |
List<string>? | [String!] |
List<string?> | [String]! |
List<string?>? | [String] |
To override nullability on list items explicitly:
<ExampleTabs> <Implementation>// Types/Book.cs
public class Book
{
[GraphQLType(typeof(ListType<NonNullType<StringType>>))]
public List<string> Genres { get; set; }
}
// Types/BookType.cs
public class BookType : ObjectType<Book>
{
protected override void Configure(IObjectTypeDescriptor<Book> descriptor)
{
descriptor
.Field(f => f.Genres)
.Type<ListType<NonNullType<StringType>>>();
}
}
Both produce genres: [String!] in the schema.