JSON.parse/stringify edge cases, streaming JSON for large payloads, JSON Schema with Ajv, MessagePack as a binary alternative, and the serialization cost at scale.
Module P-13 — JSON Internals, Serialization, and Schema Validation
What this module covers: JSON is everywhere in Node.js — request bodies, response payloads, configuration files, inter-service communication. Most developers treat it as a black box and pay for it later with silent data loss, unexpected type coercions, and performance problems at scale. This module covers what
JSON.parseandJSON.stringifyactually do under the hood, the edge cases that corrupt data silently, streaming JSON for payloads too large to hold in memory, fast serialization withfast-json-stringify, JSON Schema validation with Ajv, and when MessagePack is worth the switch.
What JSON.parse and JSON.stringify Actually Do
JSON is a text format. JSON.parse converts a string into a JavaScript object. JSON.stringify does the reverse. The key word is string — everything must pass through text.
This matters because JavaScript has types that JSON doesn't:
| JavaScript type | JSON result | What happens |
|---|---|---|
undefined | omitted | property disappears |
NaN | "null" | silently becomes null |
Infinity | "null" | silently becomes null |
Date | "2024-05-22T14:32:01.123Z" | becomes a string, not a Date on parse |
BigInt | throws TypeError | crashes your process |
Map, Set | {} | serialised as empty objects |
Symbol | omitted | property disappears |
| Circular reference | throws TypeError | crashes your process |
Safe Patterns
Handling BigInt
BigInt appears frequently when working with PostgreSQL's BIGSERIAL primary keys or blockchain IDs that exceed Number.MAX_SAFE_INTEGER (2⁵³ - 1 ≈ 9 quadrillion):
Handling Dates
JSON.stringify serialises Dates as ISO strings. JSON.parse gives you strings back. To restore Dates you need a reviver:
Detecting circular references
The replacer and reviver Parameters
JSON.stringify(value, replacer, space) — replacer controls what gets serialised:
JSON.parse(text, reviver) — reviver transforms values after parsing:
JSON.stringify Performance at Scale
At low volume, JSON.stringify is invisible. At 10,000 requests/second returning 50-field objects, it becomes measurable.
fast-json-stringify pre-compiles a serialiser from a JSON Schema — it knows the shape of the output ahead of time and skips runtime introspection:
Use this on high-traffic endpoints where you know the exact response shape. Not worth the complexity for infrequently called routes.
Streaming JSON for Large Payloads
Loading a 100,000-row query result into memory, calling JSON.stringify, and writing the result is a memory spike waiting to happen. Streaming processes rows as they arrive from the database:
For Postgres with raw SQL, use pg-query-stream:
JSON Schema Validation with Ajv
Ajv (Another JSON Schema validator) is the fastest JSON Schema validator for Node.js. JSON Schema is the standard for describing the structure of JSON data — more portable than Zod (which is TypeScript-specific) and used widely in OpenAPI and form validation.
Ajv vs Zod: Zod infers TypeScript types and is designed for TypeScript projects. Ajv follows the JSON Schema standard and is faster — it compiles schemas to optimised validation functions. For Node.js APIs already using Zod (as in P-4), stick with Zod. Ajv shines when you need JSON Schema portability (shared schemas between frontend/backend) or raw performance.
MessagePack: Binary Alternative to JSON
MessagePack is a binary serialisation format that is 20–50% smaller than JSON and faster to serialise/deserialise. It supports types that JSON doesn't: integers, floats, binary data, timestamps.
When to consider it:
- High-frequency inter-service communication (microservices)
- Real-time applications where payload size affects latency
- Storing structured data in Redis (smaller footprint)
MessagePack in Express
For most REST APIs serving browsers, JSON is the right choice — browsers speak JSON natively, the bandwidth difference is negligible, and debuggability is far better. MessagePack is the right choice for Node-to-Node communication where you control both ends and need to squeeze out latency.
The JSON.parse Cost in Hot Paths
JSON.parse parses the entire string synchronously. On the main thread. A 1MB request body takes ~5ms. At 1,000 req/s, that's 5 seconds of JSON parsing per second on one thread.
Strategies for hot paths:
- Validate size before parsing — reject oversized bodies early (
express.json({ limit: '10kb' })) - Use
fast-json-stringifyfor serialisation on high-throughput routes - Cache parsed results when the same JSON is parsed repeatedly (e.g., static configuration)
- Move heavy parsing to a worker thread for CPU-intensive transformations
Summary
undefined,NaN,Infinity,BigInt,Date,Map,Setall behave unexpectedly withJSON.stringify. Know the conversion table.- BigInt throws; serialise it as a string. Dates become strings; use a reviver to restore them. Circular references throw; use a replacer with a
WeakSet. replaceras an array is the cleanest way to whitelist response fields — prevents sensitive data leaking from the serialisation layer.fast-json-stringifypre-compiles serialisers from schemas — 4× faster than built-inJSON.stringifyfor high-throughput, fixed-shape responses.- Stream JSON for large exports using
JSONStream.stringifypiped through Prisma/pg stream results — constant memory regardless of result set size. - Ajv is fastest for JSON Schema validation; portable across languages and tools. Use it when you need JSON Schema portability. Use Zod when you want TypeScript inference.
- MessagePack is 20–50% smaller and faster than JSON. Worth it for Node-to-Node communication. Not worth it for browser-facing APIs.
Next: Dockerizing Node.js applications for production — multi-stage builds, Alpine vs slim images, non-root users, health checks, and the production readiness checklist for containerised deployments.
When dealing with a large result set from a database in Node.js, what is the best way to return it as JSON to avoid high memory consumption?
Which statement correctly describes the difference between Zod and Ajv in Node.js?
What is a primary reason to consider MessagePack over JSON in a Node.js microservice architecture?
Test your knowledge with more question sets
Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.
Sign in & RegisterDiscussion
0Join the discussion