3 minutes
JSON API Design: Should You Allow Null Values or Omit Empty Fields?
Practical trade-offs between returning explicit null values and omitting empty fields in JSON APIs, including PATCH semantics and Go struct tags.
One recurring debate when designing JSON APIs is how to represent missing or optional data: should a response (or request) include "middle_name": null, or omit the "middle_name" key altogether?
// Option A: explicit null
{
"id": "usr_123",
"first_name": "Albert",
"middle_name": null
}
// Option B: omit empty / absent fields
{
"id": "usr_123",
"first_name": "Albert"
}
Both approaches are valid JSON, and the right choice depends on whether you are designing response payloads (GET) or partial update payloads (PATCH).
null vs. Empty Values ("", 0, [])
First, null is not a substitute for an empty collection or an empty string:
- Arrays/collections should almost never be
nullin responses. Returning"items": []instead of"items": nullsaves every client from writing null checks before iterating. (In Go, initialize slices withmake([]Item, 0)or[]Item{}rather thanvar items []Item, which marshals tonull.) - Booleans and numbers should only be nullable when “unknown / not set” has a real domain meaning distinct from
falseor0.
When Returning Explicit null Makes Sense
- Predictable response shape: Consumers inspecting the payload see the full schema at a glance without checking the OpenAPI spec to know a field exists.
- Distinguishing “not set” from “not requested”: In APIs that support field selection (
?fields=id,first_name), an omitted key means the caller didn’t ask for it, whereas"middle_name": nullmeans the caller asked for it and the value is empty. - JSON Merge Patch (
PATCH— RFC 7396): In a partial update, omitting a field means “leave this field untouched”, whereas sending"middle_name": nullmeans “clear the existing value”.
When Omitting Empty Fields Makes Sense
- Smaller payloads: On wide resources with dozens of optional attributes, stripping unset fields via
omitempty(oromitzeroin Go 1.24+) reduces payload size over the wire. - Forward/backward compatibility: Adding a new optional attribute doesn’t change existing responses until that feature is populated.
- Simpler client defaults: Languages like TypeScript (
user.middleName ?? "N/A") treatundefinedcleanly when keys are omitted, whereasnulldoes not trigger default parameters (function greet(name = "Guest")still receivesnullifnullis passed!).
Practical Rules of Thumb
- Never return
nullfor arrays or objects that represent collections—return[]or{}. - Be consistent across responses: Pick either explicit
nullfor nullable scalar fields or omitted keys across your API, and documentnullable: truevsrequiredaccurately in your OpenAPI specification. - In
PATCHendpoints, treat omitted andnulldifferently: Use pointer fields or a 3-state wrapper (Unset,Null,Value) on the backend so you can tell whether the client omitted the key or explicitly sentnullto clear it.