Correctly Modeling Required Fields, Nullable Fields, and Lists in the Schema
Correctly Modeling Required Fields, Nullable Fields, and Lists in the Schema
~7 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
GraphQL types are nullable by default - every field is allowed to return null unless explicitly declared otherwise. This chapter shows how !, list brackets [...], and their combinations control this behavior - a topic that comes into direct use for the events schema in chapter 12.
The exclamation mark: Non-Null
String means "this field may be null", String! means "this field is guaranteed not to be null". If a resolver still returns null for a field declared as !, Magento doesn't respond with null in that field - it responds with a GraphQL error. The non-null guarantee is enforced at runtime, not just documented.
type Example {
id: ID! # guaranteed present
title: String! # guaranteed present
subtitle: String # may be missing (null)
}Non-Null on arguments: required parameters
The same ! also applies to arguments - there it means the client must supply this value, otherwise request validation already fails before any resolver is even called:
type Query {
productBySku(sku: String!): Product # sku is required
}Lists and their four combinations
Square brackets [...] mark a list. Combined with !, four different meanings emerge, and they're frequently confused:
[String]- the list itself may benull, and individual entries in the list may also benull.[String]!- the list itself is guaranteed to be present (at least an empty array), but individual entries may benull.[String!]- the list itself may benull, but if it's present, no entry isnull.[String!]!- both the list and every single entry are guaranteed not to benull- the strictest variant.
// Resolver for a field of type [String!]!
// -> the return value MUST be an array, and no element may be null:
return ['Monday', 'Tuesday', 'Wednesday'];
// For [String], the following would also be valid:
return null;
return ['Monday', null, 'Wednesday'];When Non-Null really pays off
At first glance, Non-Null looks harmlessly stricter and therefore "safer" - in practice, the opposite is often true. A field declared as ! that the resolver can't fill in some edge case takes the entire parent branch of the response down with it when rendering nested queries (GraphQL calls this "null bubbling"). A field that could plausibly be missing sometimes (e.g. an optional short description) should therefore stay nullable.
Achtung: Null bubbling doesn't just affect the single field: if title: String! inside an event: Event! field can't be filled, not only does title become null - the entire parent level event does too, and in the worst case the whole response. Non-Null should therefore only be used for fields that genuinely can never be missing on the business level (IDs, required values backed by a NOT NULL constraint in the database).
A rule of thumb for the upcoming events schema
Block 4 sticks to a simple guideline: columns with nullable="false" in db_schema.xml get declared as ! in the GraphQL schema (e.g. title: String!, identifier: String!), while optional columns (nullable="true", e.g. capacity) stay nullable. This 1:1 mapping between the DB schema and the GraphQL schema isn't mandated by the specification, but it's a reliable rule of thumb that avoids surprises.
Tipp: For arguments with a sensible default, a default value directly in the schema is often nicer than strict ! - pageSize: Int = 20 instead of pageSize: Int!. That way the argument stays optional without the resolver having to rebuild a fallback value itself.
With Non-Null, lists, and their combinatorics in mind, block 2 wraps up. Block 3 shows how to cleanly extend existing core types without duplicating them.