jsonjavascriptdebuggingtutorial

null vs undefined in JSON: Handle Missing Values Right

·8 min read·JSON Concepts

null vs undefined — The Core Difference

JSON is a language-independent format. It recognizes null as a valid value representing "no value." JSON does not recognize undefined — it is a JavaScript-only concept that does not exist in the JSON specification (RFC 8259).

javascript
JSON.parse("null");        // Returns null (valid)
JSON.parse("undefined");   // SyntaxError: Unexpected token u
JSON.parse('"undefined"'); // Returns the string "undefined" (valid)

This asymmetry causes bugs that are subtle and hard to diagnose, especially in API communication where the difference between a missing field and a null field has semantic meaning.

What JSON.stringify Does with undefined

This is where most bugs originate. JSON.stringify silently drops any object property whose value is undefined:

javascript
const user = {
  name: "Ravi",
  middleName: undefined,  // dropped silently
  age: 28,
  role: null,             // kept as null
};

JSON.stringify(user);
// '{"name":"Ravi","age":28,"role":null}'
// middleName is gone — no error, no warning

In arrays, undefined becomes null (because arrays are index-ordered and a missing element changes the structure):

javascript
JSON.stringify([1, undefined, 3, null]);
// '[1,null,3,null]'   — undefined → null, null stays null

Other values that JSON.stringify converts silently: - NaNnull - Infinitynull - -Infinitynull - Function values → dropped (like undefined) - Symbol values → dropped

Practical Bug Patterns

Bug 1: Optional field becomes silently absent

javascript
const body = {
  userId: user.id,
  referralCode: promoCode || undefined,  // dropped if falsy!
};

JSON.stringify(body);
// If promoCode is "" (empty string) or null:
// '{"userId":42}'   — referralCode missing entirely
// API expected: '{"userId":42,"referralCode":null}'

Fix — use null for absent optional fields:

javascript
const body = {
  userId: user.id,
  referralCode: promoCode || null,  // always present
};

Bug 2: Conditional spread creates inconsistent shape

javascript
const body = {
  userId: user.id,
  ...(promoCode ? { referralCode: promoCode } : {}),  // key sometimes missing
};
// Could send {"userId":42} or {"userId":42,"referralCode":"SAVE20"}
// API may require the field always present

Bug 3: Accessing missing nested fields

javascript
const city = data.user.address.city;
// TypeError: Cannot read properties of undefined (reading 'city')
// if data.user.address is null or undefined

Fix — optional chaining with nullish coalescing:

javascript
const city = data?.user?.address?.city ?? "Unknown";
const firstTag = data?.tags?.[0] ?? null;

Bug 4: Loose equality traps

javascript
const x = null;
x === null;       // true  — strict: null is null
x === undefined;  // false — strict: they are different
x == null;        // true  — loose: null == undefined is true
x == undefined;   // true  — same as above

Rule: use === null when you specifically mean "JSON null." Use == null when you mean "absent or unset in any way."

Safe API Response Access Pattern

javascript
// Option 1: Optional chaining (ES2020+) — preferred
const city      = response?.data?.user?.address?.city ?? "Unknown";
const accountId = response?.data?.account?.id ?? null;

// Option 2: Utility for dynamic paths
function getPath(obj, path, fallback = null) {
  return path.split(".").reduce(
    (acc, key) => (acc != null && acc !== undefined ? acc[key] : undefined),
    obj
  ) ?? fallback;
}

const email = getPath(apiResponse, "user.contact.email", "");

Converting undefined to null Before Serializing

When you must serialize objects that might contain undefined values:

javascript
function undefinedToNull(value) {
  return JSON.parse(
    JSON.stringify(value, (_, v) => (v === undefined ? null : v))
  );
}

const safe = undefinedToNull({
  name: "Ravi",
  score: undefined,
  address: { city: "Surat", zip: undefined },
});
// { name: "Ravi", score: null, address: { city: "Surat", zip: null } }

TypeScript type guard to distinguish null from undefined:

typescript
function isPresent<T>(value: T | null | undefined): value is T {
  return value !== null && value !== undefined;
}

const items = [1, null, 2, undefined, 3];
const valid = items.filter(isPresent); // [1, 2, 3], typed as number[]

Null Handling in Other Languages

PythonNone is Python's equivalent of JSON null:

python
import json
data = json.loads('{"name": "Ravi", "score": null}')
data["score"] is None  # True
data["score"] == None  # True

Go — use pointer types for nullable fields:

go
type User struct {
    Name       string  `json:"name"`
    MiddleName *string `json:"middle_name"`  // nil = JSON null or absent
}

API Design Recommendations for Null vs Absent

SituationRecommendation
Field has no value for this recordUse null — keeps the schema consistent
Field does not exist for this resource typeOmit it entirely
Optional filter in a request bodyAccept both null and absence — treat them the same
Patch endpoint (PATCH)null = clear the field; absent = do not change
Creation endpoint (POST)Require all mandatory fields; default optional ones to null

Use JSONKit's JSON Formatter to inspect API responses and verify that expected fields are present and not silently dropped.

Try JSON Formatter

Inspect how null values appear in your serialized JSON output.