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 format nearly every API, configuration file, and NoSQL database speaks. This guide covers the syntax, the six data types, how parsing 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. Crockford derived it 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.

Douglas Crockford introduced it 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 frozen: a document written in 2005 parses the same way 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 any depth, and that covers the whole 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
}

The rules: keys use double quotes (single quotes are invalid), commas separate items, and no trailing comma follows the last item.

Inside string values, you escape certain characters 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't contain a literal line break, so multi-line content encodes each newline as `\n`. You may escape the forward slash (`\/`), but almost nobody does.

The six data types

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

Strings are double-quoted Unicode text with the escapes described above. Numbers are 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 stay exact up to 9,007,199,254,740,991 (2^53 - 1). Past that, you lose precision without any error, so send large identifiers such as 64-bit snowflake IDs and account numbers as strings.

boolean is true or false, unquoted. null is an explicit empty value, which differs from a missing key. Objects and arrays hold any mix of the other types and each other, and the grammar sets no depth limit.

That's the whole type system. JSON has no date type, so timestamps travel as ISO 8601 strings or Unix epoch numbers by convention. It has no undefined and no binary data (Base64-encode it into a string). Fewer types let anyone write a correct parser in any language with little effort.

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. JSON.stringify forgives too much. It drops undefined values from objects, turns NaN and Infinity into null, converts Date objects to ISO strings, and discards functions and symbols.

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 holds in all of them: handle failure whenever you parse JSON you didn't produce. A truncated network response or a half-written file arrives with no label, and you find out through a SyntaxError.

Where JSON is used

APIs are the obvious case: REST bodies and GraphQL responses are JSON end to end, and few public HTTP APIs default to anything else. Configuration comes next: package.json, tsconfig.json, and the settings of most editors and CI systems. Databases adopted it too. MongoDB stores documents as BSON (a binary JSON variant), PostgreSQL has native json and jsonb columns, and Redis values are often JSON strings.

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 JSON to move records between services that share no other type system. If two programs need to exchange data and nobody wants to negotiate a format, developers pick JSON.

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 inside string values. Each one throws a SyntaxError, and the reported position marks where the parser gave up. That spot often sits one token after the real mistake, which makes trailing commas annoying to track down.

Duplicate keys cause a quieter bug. `{ "id": 1, "id": 2 }` parses fine: the spec says names should be unique but doesn't require parsers to enforce it, and JSON.parse keeps the last value without complaint. An upstream merge that duplicates a key ships the wrong data with no error anywhere. Format the JSON before you review it, one key per line with consistent indentation, and you'll spot both kinds of mistake in seconds.

Beyond plain JSON

Plain JSON allows no comments, no trailing commas, and one document per file. Those limits spawned a family of supersets and conventions. JSONC adds comments, and VS Code settings and tsconfig.json accept it. JSON5 goes further with unquoted keys, single quotes, trailing commas, and hex numbers. JSON Lines (NDJSON) puts 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 come from mixed conventions, such as an API returning camelCase while a client looks up snake_case, and they show up as undefined values instead of 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 stay exact only up to 9,007,199,254,740,991 (2^53 - 1). JavaScript rounds larger values the moment it 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