Nullable vs Non-Nullable Types
In GraphQL, every field is nullable by default — a String field can resolve to null unless it's explicitly marked with a trailing exclamation mark as String!, meaning the server promises it will never return null for that field. This inverts the assumption many REST APIs implicitly make; GraphQL forces the schema author to be deliberate about which fields are guaranteed and which are optional, and that guarantee becomes part of the public contract clients can rely on without defensive null-checking.
Cricket analogy: A player's 'currentTeam' field might be null for a retired player, but 'name' should never be null for a valid player record — just as GraphQL lets a schema author mark certain fields as always-present (name: String!) while others stay optional.
Error Propagation and Null Bubbling
The real power of non-null types shows up during error handling: if a resolver for a non-null field (Type!) throws an error or returns null unexpectedly, GraphQL doesn't just null out that single field — it propagates the null upward to the nearest nullable ancestor field, potentially nulling out an entire object or list to preserve the schema's guarantee. This 'null bubbling' means a single failed non-null leaf field can wipe out much more of the response than expected, so schema authors have to weigh the convenience of a strict guarantee against the blast radius of a single resolver failure.
Cricket analogy: If a mandatory 'runsScored' stat fails to load for one ball in an over, and the field is marked non-null, the whole over's data can be wiped from the response rather than just that one ball — like GraphQL's null bubbling escalating a single failure upward.
type Team {
id: ID!
name: String!
currentSponsor: String # nullable — a team may have no sponsor
}
type Match {
id: ID!
homeTeam: Team! # non-null — a match always has a home team
result: String # nullable — result is null before the match ends
}
query {
match(id: "m-102") {
homeTeam {
name
}
result
}
}A common pattern is to make list items non-null but the list itself nullable ([Player!]) — an empty or absent list is still valid, but if the list exists, none of its entries should ever be null, which is a stronger and more common guarantee than [Player]! or [Player!]!.
Overusing ! on fields backed by unreliable data sources (flaky third-party APIs, optional joins) is a common mistake — a single transient failure on a deeply-nested non-null field can null out a much larger portion of the response than the actual failure warrants, degrading the client experience more than a nullable field with a documented 'may be null on error' contract would.
- Fields are nullable by default in GraphQL;
!marks a field as guaranteed non-null. - Non-null is a promise the schema author makes to clients, allowing them to skip defensive null checks.
- If a non-null field's resolver errors or returns null, GraphQL bubbles the null up to the nearest nullable ancestor.
- Null bubbling can null out an entire object or list because of a single deeply-nested non-null failure.
[Type!](nullable list of non-null items) is a common, safer pattern than a fully non-null list.- Overusing
!on fields backed by unreliable data sources increases the blast radius of a single failure.
Practice what you learned
1. What is the default nullability of a GraphQL field if no modifier is applied?
2. What happens when a resolver for a non-null field returns null or throws an error?
3. What does `[Player!]` mean as opposed to `[Player]!`?
4. Why is overusing `!` on fields backed by unreliable data sources risky?
5. What benefit does a non-null field give to client developers?
Was this page helpful?
You May Also Like
The Type System In Depth
A deep dive into how GraphQL's schema — scalars, object types, input types, and list/non-null modifiers — forms the typed contract between client and server.
Enums in GraphQL
How GraphQL enums restrict fields and arguments to a fixed, validated set of named values, and how their SDL names map to internal server representations.
Custom Scalars
How to model domain-specific leaf values beyond GraphQL's five built-in scalars using serialize, parseValue, and parseLiteral.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics