Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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 be null, and individual entries in the list may also be null.
  • [String]! - the list itself is guaranteed to be present (at least an empty array), but individual entries may be null.
  • [String!] - the list itself may be null, but if it's present, no entry is null.
  • [String!]! - both the list and every single entry are guaranteed not to be null - 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.