DEV Community

Cover image for Why JSON.stringify Removes Undefined Values
Nilesh Raut
Nilesh Raut

Posted on

Why JSON.stringify Removes Undefined Values

You log an object before sending it to an API:

const user = {
  id: 1,
  name: "John",
  email: undefined
};

console.log(user);
Enter fullscreen mode Exit fullscreen mode

Output:

{
  id: 1,
  name: "John",
  email: undefined
}
Enter fullscreen mode Exit fullscreen mode

Everything looks fine.

Then you serialize it:

const json = JSON.stringify(user);

console.log(json);
Enter fullscreen mode Exit fullscreen mode

Output:

{"id":1,"name":"John"}
Enter fullscreen mode Exit fullscreen mode

The email field disappears completely.

No error.

No warning.

No indication that data was removed.

This behavior surprises many developers the first time they encounter it, especially when debugging API payloads or caching systems.


Problem

JSON.stringify() does not preserve undefined values.

Consider:

const payload = {
  username: "john",
  age: undefined,
  city: undefined
};

console.log(JSON.stringify(payload));
Enter fullscreen mode Exit fullscreen mode

Output:

{"username":"john"}
Enter fullscreen mode Exit fullscreen mode

The properties with undefined values are omitted entirely.

This can create unexpected behavior when:

  • Sending API requests
  • Updating database records
  • Caching objects
  • Comparing payloads
  • Generating audit logs

Why It Happens

The behavior comes from the JSON specification itself.

JSON supports only a limited set of data types:

  • String
  • Number
  • Boolean
  • Null
  • Object
  • Array

It does not support:

  • undefined
  • Functions
  • Symbols

Because undefined is not a valid JSON value, JSON.stringify() excludes it from objects.

Example:

const data = {
  name: "John",
  age: undefined
};

console.log(JSON.stringify(data));
Enter fullscreen mode Exit fullscreen mode

Result:

{"name":"John"}
Enter fullscreen mode Exit fullscreen mode

The property is removed because JSON has no representation for undefined.


Example

Imagine a profile update API.

Frontend payload:

const updateData = {
  firstName: "John",
  lastName: undefined
};
Enter fullscreen mode Exit fullscreen mode

Serialized request:

JSON.stringify(updateData);
Enter fullscreen mode Exit fullscreen mode

Produces:

{
  "firstName": "John"
}
Enter fullscreen mode Exit fullscreen mode

The backend never receives lastName.

Now the server cannot distinguish between:

{
  lastName: undefined
}
Enter fullscreen mode Exit fullscreen mode

and:

{}
Enter fullscreen mode Exit fullscreen mode

Both become:

{}
Enter fullscreen mode Exit fullscreen mode

This distinction matters in partial update operations.


Production Ready Solution

Convert Undefined to Null

If you need fields to remain present, explicitly convert them.

const payload = {
  name: "John",
  email: undefined
};

const json = JSON.stringify(payload, (key, value) =>
  value === undefined ? null : value
);
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "name": "John",
  "email": null
}
Enter fullscreen mode Exit fullscreen mode

The field remains visible.


Create a Reusable Serializer

In larger codebases, repeating replacer functions becomes messy.

A helper works better:

function safeStringify(data) {
  return JSON.stringify(data, (key, value) =>
    value === undefined ? null : value
  );
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const result = safeStringify(payload);
Enter fullscreen mode Exit fullscreen mode

This keeps behavior consistent across services.


Define Clear API Semantics

In production APIs, it's important to define what each value means.

For example:

{
  "email": null
}
Enter fullscreen mode Exit fullscreen mode

might mean:

  • Remove email

while

{}
Enter fullscreen mode Exit fullscreen mode

might mean:

  • Leave email unchanged

Without clear rules, clients and servers often interpret missing fields differently.


Validate Before Serialization

Sometimes the best solution is removing invalid data intentionally.

Example:

function removeUndefined(obj) {
  return Object.fromEntries(
    Object.entries(obj).filter(
      ([_, value]) => value !== undefined
    )
  );
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const cleaned = removeUndefined(data);
Enter fullscreen mode Exit fullscreen mode

Now the omission is explicit instead of happening silently.


Common Mistakes

Assuming Undefined Becomes Null

Many developers expect:

{
  email: undefined
}
Enter fullscreen mode Exit fullscreen mode

to become:

{
  "email": null
}
Enter fullscreen mode Exit fullscreen mode

That never happens automatically.

The property is removed entirely.


Debugging the Wrong Object

This is common:

console.log(payload);
Enter fullscreen mode Exit fullscreen mode

shows:

{
  email: undefined
}
Enter fullscreen mode Exit fullscreen mode

Then:

JSON.stringify(payload);
Enter fullscreen mode Exit fullscreen mode

removes the field.

Developers often inspect the original object and assume the serialized payload contains the same data.

Always inspect the final JSON string.


Losing Fields During PATCH Requests

Suppose a frontend sends:

{
  phone: undefined
}
Enter fullscreen mode Exit fullscreen mode

After serialization:

{}
Enter fullscreen mode Exit fullscreen mode

The backend may interpret this as:

  • No changes requested

instead of:

  • Remove phone number

This can lead to subtle update bugs.


Forgetting Nested Objects

The behavior applies recursively.

Example:

const user = {
  profile: {
    bio: undefined
  }
};

console.log(JSON.stringify(user));
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "profile": {}
}
Enter fullscreen mode Exit fullscreen mode

Nested properties disappear as well.


Debugging Tips

When data seems to vanish during API calls, check the serialized payload first.


Log the Actual JSON

Instead of:

console.log(payload);
Enter fullscreen mode Exit fullscreen mode

use:

console.log(JSON.stringify(payload));
Enter fullscreen mode Exit fullscreen mode

This reveals exactly what will be transmitted.


Compare Before and After

console.log("Original:", payload);

console.log(
  "Serialized:",
  JSON.stringify(payload)
);
Enter fullscreen mode Exit fullscreen mode

The difference is often immediately obvious.


Inspect Network Requests

In browser developer tools:

  • Open Network tab
  • Select request
  • Check Request Payload

Many developers spend hours debugging backend code when the field was already removed by JSON.stringify() on the client.


Watch for ORM Updates

Some ORMs treat:

null
Enter fullscreen mode Exit fullscreen mode

and

undefined
Enter fullscreen mode Exit fullscreen mode

very differently.

Examples include:

  • MongoDB drivers
  • Prisma
  • Sequelize
  • TypeORM

Verify how your persistence layer handles missing properties versus explicit null values.


Performance Considerations

The default JSON.stringify() implementation is highly optimized.

Using a replacer function:

JSON.stringify(data, replacer)
Enter fullscreen mode Exit fullscreen mode

introduces additional processing because every property is inspected.

For normal API payloads, the overhead is negligible.

For very large objects:

  • Cache transformed objects when possible
  • Avoid unnecessary serialization cycles
  • Benchmark large datasets before introducing custom replacers everywhere

In most production systems, correctness matters far more than the tiny performance cost.


Final Thoughts

JSON.stringify() is not removing undefined values by accident.

It's following the JSON specification.

The key thing to remember is:

{
  email: undefined
}
Enter fullscreen mode Exit fullscreen mode

becomes:

{}
Enter fullscreen mode Exit fullscreen mode

not:

{
  "email": null
}
Enter fullscreen mode Exit fullscreen mode

Whenever a field must remain visible after serialization, convert undefined to a valid JSON value such as null.

Understanding this behavior can save a surprising amount of debugging time, especially when working with APIs, databases, caching layers, and distributed systems where missing fields and null values often have very different meanings.

For more JavaScript and Node.js debugging articles based on real production issues, I occasionally publish deep dives on NileshBlog and TechNilesh when a bug is interesting enough to document.

Top comments (0)