Skip to content
jsonforge.app
Back to blog
Guide10 min read

What is JSON? A Complete Beginner's Guide

JSON (JavaScript Object Notation) is the lingua franca of the modern web — the format nearly every API, configuration file, and NoSQL database speaks. This guide walks through the syntax, the six data types, how parsing actually behaves in code, and the predictable ways hand-written JSON goes wrong.

What is JSON?

JSON is a text-based format for representing structured data. It was derived from JavaScript's object-literal syntax, but it's language-agnostic: nearly every programming language ships a JSON parser in its standard library. A JSON document is a sequence of Unicode characters — you can read it in any editor, store it in a text column, or send it over a socket with no special handling.

It was introduced by Douglas Crockford in the early 2000s as a simpler alternative to XML. Today it's an international standard with two equivalent specifications — ECMA-404 and IETF RFC 8259 — so the grammar is genuinely frozen: a document written in 2005 parses identically today. The standard media type is application/json, and the usual file extensions are .json and, for line-delimited files, .jsonl.

JSON syntax basics

JSON has two structures: objects (key/value maps wrapped in curly braces) and arrays (ordered lists wrapped in square brackets). Keys must be double-quoted strings; values can be any of the six data types. The two structures nest inside each other to arbitrary depth — that's the entire structural vocabulary.

A typical JSON object — keys are double-quoted strings.
json
{
  "name": "Alice",
  "age": 30,
  "active": true,
  "roles": ["admin", "editor"],
  "address": {
    "city": "San Francisco",
    "zip": "94102"
  },
  "metadata": null
}

Note the rules: keys use double quotes (single quotes are invalid), items are separated by commas, and there's no trailing comma after the last item.

Inside string values, certain characters must be escaped with a backslash: the double quote (`\"`), the backslash itself (`\\`), and control characters like newline (`\n`), tab (`\t`), and carriage return (`\r`). Everything else can appear raw, including emoji and text in any script. A string can never contain a literal line break — multi-line content encodes each newline as `\n`. The forward slash may be escaped (`\/`) but almost never is.

The six data types

JSON supports exactly six data types: string, number, boolean, null, object, and array. Four are scalars; the two structural types do all the composing.

Strings are double-quoted Unicode text with the escapes described above. Numbers are always decimal, IEEE-754 double-precision — JSON doesn't distinguish integers from floats, has no hexadecimal or octal notation, and forbids NaN and Infinity (exponent forms like 1.5e3 are fine). Integers are exact only up to 9,007,199,254,740,991 (2^53 - 1); beyond that, precision silently degrades, which is why very large identifiers — 64-bit snowflake IDs, account numbers — should travel as strings.

boolean is true or false, unquoted. null is an explicit empty value — not the same thing as a missing key. Objects and arrays hold any mix of the other types and each other, with no depth limit in the grammar.

That's the whole type system, and its minimalism is the point. There is no date type — timestamps travel as ISO 8601 strings or Unix epoch numbers by convention. There's no undefined and no binary data (Base64-encode it into a string). Fewer types means a parser that's trivial to implement correctly in every language.

Parsing and producing JSON in practice

In JavaScript the pair is JSON.parse and JSON.stringify. JSON.parse is strict — invalid input throws a SyntaxError and nothing else. JSON.stringify is forgiving to a fault: undefined values are dropped from objects, NaN and Infinity become null, Date objects become ISO strings, and functions and symbols vanish entirely.

JSON.parse throws on bad input; stringify's later arguments control formatting.
typescript
const text = '{"name": "Alice", "age": 30}';

let user;
try {
  user = JSON.parse(text); // throws SyntaxError on invalid input
} catch (err) {
  console.error("Not valid JSON:", err.message);
}

// Serialize — a third argument pretty-prints with an indent
const pretty = JSON.stringify(user, null, 2);
const compact = JSON.stringify(user); // minified, single line

Every runtime exposes the same pair under different names — json.loads/json.dumps in Python, encoding/json in Go, serde_json in Rust. One rule is universal: never parse JSON you didn't produce without handling failure. A truncated network response or a half-written file doesn't arrive with a label; it arrives as a SyntaxError.

Where JSON is used

APIs are the obvious case: REST bodies and GraphQL responses are JSON end to end, and it's rare to find a public HTTP API that defaults to anything else. Configuration is next — package.json, tsconfig.json, and the settings of most editors and CI systems. Databases leaned in too: MongoDB stores documents as BSON (a binary JSON variant), PostgreSQL has native json and jsonb columns, and Redis values are very often JSON strings.

Beyond the obvious: structured logs ship as one JSON object per line (JSON Lines), JWT tokens are Base64URL-encoded JSON objects, server-sent events carry JSON payloads, and data pipelines use it to move structured records between services that share no other type system. When two pieces of software need to exchange data and nobody wants to negotiate a format, JSON is the default answer.

Common beginner mistakes

Hand-written JSON fails in predictable ways: single quotes instead of double quotes, unquoted keys (legal in JavaScript, illegal in JSON), trailing commas after the last item, comments pasted in from documentation, and literal newlines pasted into string values. Each one throws a SyntaxError, and the reported position is where the parser gave up — often one token after the actual mistake, which makes trailing commas especially annoying to track down.

The quieter bug is duplicate keys. `{ "id": 1, "id": 2 }` is not a parse error: the spec says names should be unique but doesn't require parsers to enforce it, and JSON.parse silently keeps the last value. An upstream merge that duplicates a key ships the wrong data with no error anywhere. Formatting JSON before reviewing it — one key per line, consistent indentation — makes both classes of mistake visible in seconds.

Beyond plain JSON

Plain JSON's limits — no comments, no trailing commas, one document per file — spawned a family of supersets and conventions. JSONC adds comments and is what VS Code settings and tsconfig.json actually accept. JSON5 goes further: unquoted keys, single quotes, trailing commas, hex numbers. JSON Lines (NDJSON) is a convention for many documents in one file, one per line. All of them interoperate with plain JSON at the data level — strip the syntax extensions and you're back to the standard grammar.

FAQ

Is JSON the same as a JavaScript object?
No. A JavaScript object literal can contain functions, comments, single-quoted strings, and trailing commas. JSON is stricter: double-quoted keys, no functions, no comments. Every valid JSON document is a valid JavaScript expression, but not vice versa.
Can JSON contain comments?
Standard JSON cannot. Some tools (like VS Code's JSONC) allow comments as an extension, but a strict parser like JSON.parse() will reject them. If you need comments, consider JSON5, YAML, or JSONC.
What's the difference between JSON and XML?
JSON is lighter (no closing tags), maps directly to native data structures, and is faster to parse. XML is more verbose but supports attributes, namespaces, and schemas natively. JSON won for APIs; XML survives in document-heavy domains.
Is JSON case-sensitive?
Yes. "Name" and "name" are two different keys, and an object containing both is valid JSON. Bugs here usually come from mixed conventions — an API returning camelCase while a client looks up snake_case — and they surface as undefined values rather than errors. Pick one casing convention per API and enforce it in review.
Why did my large number lose precision?
JSON numbers are IEEE-754 double-precision, so integers are only exact up to 9,007,199,254,740,991 (2^53 - 1). Values beyond that get rounded the moment JavaScript parses them. Serialize identifiers and amounts that must round-trip exactly as strings, and convert to BigInt or a decimal type after parsing.

Try these tools

Related articles