JSON (JavaScript Object Notation) is a language-independent text format for structured data that represents values as objects, arrays, strings, numbers, booleans and null. Among data formats, it is the default choice for web APIs, configuration files and document databases because it is compact, human-readable and supported by virtually every programming language.
The format is defined by ECMA-404 and RFC 8259, which fix a deliberately small grammar. That minimalism is the source of its strengths, such as easy parsing and broad interoperability, and of its weaknesses, such as no comments, no date type and loosely specified numbers.
How JSON represents data
A JSON document is a single value, which in practice is usually an object or an array. An object is an unordered set of name and value pairs enclosed in braces, where every name is a double-quoted string. An array is an ordered list of values enclosed in brackets, and values of different types may be mixed freely.
Values nest without limit in the grammar, so a JSON document forms a tree structure. Whitespace between tokens is insignificant, which lets the same data be written as minified output for transport or pretty-printed output for people. Text exchanged between systems must be encoded as UTF-8, and strings escape control characters and quotes with a backslash.
The following table lists the six value types and the details that most often cause interoperability errors.
| Value type | Syntax | Practical note |
|---|---|---|
| Object | {“id”: 7, “name”: “Ana”} | Duplicate names are allowed by the grammar but behave unpredictably |
| Array | [1, “two”, true] | Order is significant and preserved |
| String | “text with \u00e9” | Double quotes only; Unicode escapes use \u |
| Number | -12.5e3 | No NaN, no Infinity, no leading zeros, no hexadecimal |
| Boolean | true or false | Lowercase literals only |
| Null | null | Often confused with an absent field |
Parsing, numbers and precision
A JSON parser converts text into native structures, typically maps, lists and primitive values. Because the specification does not define numeric precision, most parsers map numbers to IEEE 754 double-precision floats. Integers beyond 2^53 (about 9 quadrillion) therefore lose exactness in JavaScript and in many other runtimes.
Large identifiers, monetary amounts and high-precision timestamps should therefore be transmitted as strings or handled by a parser configured for arbitrary precision. Dates have no native type, so the common convention is an ISO 8601 string such as “2026-11-09T17:40:48Z”. Binary data must be Base64-encoded, which adds roughly one third to its size.
Two parsing models dominate. A tree parser loads the whole document into memory and is simple to use, while a streaming parser emits tokens incrementally and keeps memory flat for documents of hundreds of megabytes or more.
JSON compared with related data formats
JSON sits between verbose markup formats and binary analytical formats. It is richer than CSV because it handles nesting, simpler than XML because it has no attributes or namespaces, and far less efficient than columnar formats for large scans. The table summarizes where each format fits.
| Format | Structure | Encoding | Typical use |
|---|---|---|---|
| JSON | Nested objects and arrays | Text | APIs, configuration, document stores |
| NDJSON | One JSON value per line | Text | Logs, streaming, bulk loading |
| CSV | Flat rows and columns | Text | Spreadsheets, simple exports |
| XML | Elements, attributes, namespaces | Text | Documents, legacy enterprise exchange |
| YAML | Indentation-based superset of JSON | Text | Human-edited configuration |
| Parquet | Columnar with typed schema | Binary | Analytics on large datasets |
| Apache Arrow | Columnar in-memory layout | Binary | Zero-copy exchange between engines |
A practical rule is that JSON is the interchange format at the edges of a system, where readability and compatibility matter most, while Parquet or Arrow take over inside analytical pipelines where volume and scan speed dominate.
Schemas and validation
Plain JSON carries no schema, so a receiver cannot know from the syntax alone which fields are required or what types they must have. JSON Schema fills that gap with a vocabulary for declaring types, required properties, value ranges, string patterns and nested structures, and it underpins API description formats such as OpenAPI.
Validation should happen at every trust boundary: when an API receives a request, when a pipeline ingests a file and when a configuration is loaded. Schema evolution follows the usual compatibility rules, so adding optional fields is safe, while renaming or retyping fields breaks existing consumers.
Several variants extend or constrain the base format for specific needs, as the next table shows.
| Variant | What it adds or changes | When it applies |
|---|---|---|
| NDJSON or JSON Lines | Newline-delimited records | Appendable logs and streaming ingestion |
| JSON5 and JSONC | Comments, trailing commas | Human-edited configuration files |
| JSON-LD | Linked-data context and identifiers | Structured metadata and knowledge graphs |
| GeoJSON | Standard geometry objects | Geographic features and maps |
| BSON and CBOR | Binary encoding with extra types | Compact storage and constrained devices |
Pitfalls and good practice
Most JSON problems arise from what the specification leaves open. The following table pairs frequent symptoms with their causes and the usual fix.
| Symptom | Cause | Fix |
|---|---|---|
| Identifier changes after parsing | Integer above 2^53 | Send large IDs as strings |
| Parser rejects a config file | Comments or trailing commas | Use strict JSON or a JSON5 parser |
| Inconsistent field values | Duplicate object keys | Reject duplicates during validation |
| Timestamps shift between systems | Ambiguous date strings | Use ISO 8601 with a time zone offset |
| Memory exhaustion on import | Tree parsing of huge files | Use a streaming parser or NDJSON |
| Code execution risk | Evaluating JSON as code | Always use a dedicated parser |
Teams should also distinguish null from a missing field explicitly in their contracts, because many clients treat the two differently. For storage and analytics at scale, repeated field names inflate size, so compression or a conversion to a columnar format is usually worthwhile.
In plain words
JSON is a shared way of writing down information so that different programs can read it. It looks a little like a filled-in form: each piece of information has a label, such as “name” or “price”, followed by its value.
Lists go inside square brackets, and groups of labeled values go inside curly braces. Because it is plain text, a person can open it and understand it, and almost every programming language can read and write it without extra effort. That is why apps and websites use it constantly to exchange data behind the scenes.
A real-world example
A mobile banking app requests a customer’s recent transactions from its server. The server replies with a JSON object containing an array of 50 transactions, each with an identifier, an amount, a currency code and an ISO 8601 timestamp.
During testing, the team notices that some transaction identifiers change by a few digits on the client. The identifiers are 64-bit integers above 2^53, and the JavaScript parser rounds them. The team changes the contract so that identifiers and amounts are sent as strings, adds a JSON Schema that marks these fields as required strings, and validates every response in automated tests.
The outcome is a stable, precisely typed API contract: identifiers no longer drift, amounts keep their exact decimal value, and schema violations are caught before release rather than reported by customers.