Skip to content
JSON Tidy
Learn JSON / JSON format

JSON format: syntax rules, data types, and examples

JSON is plain text built from two structures: objects, which hold name/value pairs in curly braces, and arrays, which hold ordered lists in square brackets. Names and strings go in double quotes, and a comma separates each item from the next, with no comma after the last one.

Format your own JSON
{
  "city": "Denver",
  "temperatureC": 18.5,
  "isDaytime": true,
  "alerts": [],
  "airQuality": null
}

This one object holds a string ("Denver"), a number (18.5), a boolean (true), an array ([], empty here), and null. With the object itself, that’s all six JSON types. Both layouts are the same data: spaces and line breaks between values don’t change anything.

The rest of this guide uses a fuller version of the same forecast.

Reading a JSON document

Here’s what a forecast service might return when you ask about Denver:

{
  "location": {
    "city": "Denver",
    "latitude": 39.7392,
    "longitude": -104.9903
  },
  "updatedAt": "2026-09-29T14:00:00Z",
  "current": {
    "temperatureC": 18.5,
    "condition": "Partly cloudy",
    "windKph": 12,
    "isDaytime": true
  },
  "hourly": [
    {
      "time": "2026-09-29T15:00:00Z",
      "temperatureC": 19.1,
      "chanceOfRain": 0.1
    },
    {
      "time": "2026-09-29T16:00:00Z",
      "temperatureC": 19.4,
      "chanceOfRain": 0.25
    }
  ],
  "alerts": [],
  "stationId": "0457",
  "airQuality": null
}

The whole response is a single object, marked by the outer curly braces. Each member inside has a name in double quotes, a colon, and a value. Some values are simple: updatedAt is a string and airQuality is null. Others are containers. location and current are objects in their own right, hourly is an array with one object per hour, and alerts is an array that happens to be empty.

To point at a value, follow the names and positions down. location.city is "Denver". hourly[1].chanceOfRain is 0.25, the second hour, because array positions start at zero. JavaScript, Python, and command-line tools such as jq all address nested JSON this way. In jq, you’d write .hourly[1].chanceOfRain.

Objects hold things with named properties, and arrays hold lists where order matters. Most APIs combine them the way this one does: an object at the top level so each part has a name, and an array wherever there’s a list. Open this forecast in the formatter to fold sections or browse it as a tree.

JSON syntax rules

  • Names are strings in double quotes. {city: "Denver"} and {'city': 'Denver'} are valid JavaScript, but not valid JSON.
  • Colons and commas do the joining. A colon separates a name from its value. A comma separates one member or array item from the next, and there’s no comma after the last one.
  • Strings use double quotes only. Single quotes and backticks aren’t allowed.
  • The literals are lowercase and unquoted: true, false, and null.
  • A document holds exactly one value. Two objects one after another aren’t a valid document. JSON Lines handles that case.
  • Whitespace between tokens doesn’t matter. {"city":"Denver"} on one line is the same data as the indented version. Pretty-printing and minifying only change how it looks.

Most invalid JSON comes from writing it by hand as if it were JavaScript. This snippet has eight mistakes:

{
  location: {city: 'Denver'},
  "current": {"temperatureC": 18.5, "isDaytime": True,},
  "stationId": 0457,
  "airQuality": undefined // no sensor yet
}
  1. location isn’t in quotes.
  2. city isn’t in quotes either.
  3. 'Denver' uses single quotes.
  4. True is capitalized.
  5. There’s a trailing comma after the isDaytime value.
  6. 0457 starts with a zero, which JSON numbers can’t do.
  7. undefined isn’t a JSON value.
  8. The // comment isn’t allowed.

Here’s the corrected version:

{
  "location": {"city": "Denver"},
  "current": {"temperatureC": 18.5, "isDaytime": true},
  "stationId": "0457",
  "airQuality": null
}

The JSON Tidy validator points to the line of the first error and can repair common mistakes like these. Trailing commas cause so many problems that they have their own guide, and the JSON errors reference explains each parser message.

JSON data types

JSON has six kinds of value, and the forecast uses all of them. When a program parses the text, each one becomes that language’s closest equivalent:

TypeIn the forecastJavaScriptPython
String"Partly cloudy"stringstr
Number18.5numberint or float
Booleantruebooleanbool
NullnullnullNone
Objectlocationobjectdict
Arrayhourlyarraylist

Types are exact. 18.5 is a number and "18.5" is a string, and true is a boolean but "true" is text. A consumer expecting one will often reject the other, even though both are valid JSON.

Strings and escaping

Inside a string, a backslash starts an escape sequence. You need one for a double quote (\"), a backslash (\\), and control characters such as a newline (\n) or tab (\t). A string can’t contain a raw line break. Any character can also be written as \u plus four hex digits:

{"note": "Station \"Denver-7\"\nReadings in \u00b0C"}

That decodes to Station "Denver-7" on one line and Readings in °C on the next. Characters outside the first 65,536 code points, including most emoji, take two escapes: 🌧 is \ud83c\udf27. RFC 8259 requires JSON exchanged between systems to be UTF-8, so you can usually type ° directly. The \u form mainly helps when a tool along the way can only handle ASCII. To turn raw text into a correctly escaped JSON string, or to reverse it, use the escape and unescape tool.

Numbers

JSON has one number type: an optional minus sign, digits, an optional fraction, and an optional exponent. 18.5, -104.9903, 0.25, and 1.2e3 are all valid. 0457 (leading zero), .5 and 5. (need a digit either side of the point), +3, 0xFF, NaN, and Infinity are not.

The format puts no limit on size or precision, but the program reading it does. JavaScript stores every number as a 64-bit float, which holds whole numbers exactly only up to 9,007,199,254,740,991. Parse {"id": 9007199254740993} in a browser and you get back 9007199254740992, with no error. Python keeps it exact, so the same document can mean different things to different clients. That’s why many APIs send large IDs as strings.

stationId is a string for a related reason. It’s a label, not a quantity, and its leading zero matters. Postal codes, phone numbers, and account numbers belong in strings too. For money, use integer cents or a decimal string, because floating-point arithmetic gives 0.1 + 0.2 = 0.30000000000000004.

Booleans, null, and missing values

isDaytime: true is a plain yes/no. What’s worth thinking about is the difference between the ways of saying “nothing.” airQuality: null says the service knows about air quality but has no reading right now. alerts: [] says there are currently zero alerts. If airQuality were left out entirely, a reader couldn’t tell whether the service doesn’t support it or simply didn’t send it. Choose what each form means in your data and use it consistently.

What JSON can’t express

JSON deliberately has very few types. For anything else, the sender and receiver have to agree on a convention.

  • Dates and times are usually ISO 8601 strings, like "2026-09-29T14:00:00Z" in the forecast. The Z means UTC, the format sorts correctly as plain text, and every mainstream language can parse it. Avoid "09/29/2026", which reads differently in different countries. If you use Unix timestamps, document whether they’re in seconds or milliseconds.
  • Comments were left out on purpose. Crockford has said he removed them because people were using them to hold parser instructions. Some config formats accept comments anyway: VS Code settings and tsconfig.json use JSONC (JSON with comments), and other tools read JSON5. These files are a superset of JSON, and a strict JSON parser will reject them. To turn a JSONC file into plain JSON, use JSONC to JSON.
  • undefined, functions, NaN, and Infinity have no JSON form. JavaScript’s JSON.stringify silently drops members whose value is undefined or a function, and writes NaN and Infinity as null. If data seems to disappear when you save it, this is a common cause.
  • Binary data, such as an image, is typically Base64-encoded into a string. That makes it about a third larger, so APIs often send a URL to the file instead.

Designing JSON other people can use

Valid JSON can still be awkward to work with. These habits make it easier on whoever reads it, and the forecast follows all of them:

  • Pick one naming style. The forecast uses camelCase throughout. snake_case works just as well; mixing the two means readers have to check every name.
  • Make units obvious. temperatureC and windKph answer the question a bare "temperature": 18.5 would raise.
  • Keep each field’s type stable. If chanceOfRain is sometimes 0.25 and sometimes "25%", every consumer needs extra code to handle both.
  • Use arrays for lists. Numbered names like hour1 and hour2 can’t be looped over or counted, and you can’t add another hour without a new name.
  • Put an object at the top level. Sending {"hourly": [...]} instead of a bare array leaves room to add updatedAt or paging details later without breaking existing clients.
  • Don’t rely on member order or repeat a name. Objects are unordered, and some storage reorders them: PostgreSQL’s jsonb type does. Parsers also disagree about duplicate names. JavaScript and Python keep the last value, others keep the first or raise an error.
  • Write the shape down. A JSON Schema records which fields are required and what types they hold, so both sides can validate against the same rules. You can check data against one with the JSON Schema validator.

Where JSON is used

Web APIs are the main place. A server sends the forecast with a Content-Type: application/json header, and the client turns the text into native objects with one call:

// JavaScript
const forecast = await response.json();   // or JSON.parse(text)
forecast.hourly[1].chanceOfRain;           // 0.25

# Python
forecast = json.loads(text)
forecast["hourly"][1]["chanceOfRain"]      # 0.25

Configuration files such as package.json and composer.json use JSON because every language can read it without extra libraries.

Logs and large datasets often use JSON Lines (.jsonl, also called NDJSON). Each line is a complete JSON value, so a program can append records without rewriting the file and process them one at a time.

Databases store it directly. PostgreSQL has json and jsonb column types, and MongoDB stores documents in BSON, a binary format modeled on JSON.

Login tokens are often JWTs. A JWT is three Base64url-encoded parts separated by dots, and the first two decode to JSON objects describing the token and the user. Anyone can decode them. The signature proves who issued the token, but it doesn’t hide the contents. Learn how JWTs work, or inspect one with the JWT decoder.

When JSON needs to fit into a spreadsheet, nested objects have to become columns. The nested JSON to CSV guide shows how that works, and CSV to JSON goes the other way.

JSON vs XML and YAML

Here are the forecast’s current conditions in the other two common text formats:

XML

<current>
  <temperatureC>18.5</temperatureC>
  <condition>Partly cloudy</condition>
  <isDaytime>true</isDaytime>
</current>

YAML

current:
  temperatureC: 18.5
  condition: Partly cloudy
  isDaytime: true

XML is older and more verbose. Every value is text unless a schema says otherwise, so 18.5 and true aren’t really a number and a boolean. XML has attributes, namespaces, and mixed text-and-markup content, which make it a better fit for documents than for records. SVG, RSS, and the files inside a .docx are XML. Many older enterprise and SOAP APIs still use it.

YAML is built for humans editing configuration: it uses indentation instead of brackets and allows comments. YAML 1.2 is designed so that almost any JSON document is also valid YAML. The trade-off is surprising behavior. Indentation mistakes change the structure, and older YAML 1.1 parsers read the bare value no (for example, Norway’s country code) as false. It’s the usual choice for Kubernetes, Docker Compose, and CI pipelines. To move a file between the two, use JSON to YAML or YAML to JSON.

For data passed between programs, JSON is the usual default. It has real types, parsers exist in every language, and browsers include one.

Frequently asked questions

Is a JSON file just a text file?

Yes. A .json file is plain text, normally saved as UTF-8, that follows JSON’s rules. Any text editor can open and change it; the rules only matter to the program that reads it.

How do I open a .json file?

Any text editor works, such as Notepad, TextEdit, or VS Code, and most browsers show JSON files too. If the file is one long line, open it in a JSON formatter to see it with indentation.

How do you make a JSON file readable?

Format it. Formatting adds line breaks and indentation without changing the data. Paste it into a JSON formatter, or in code use JSON.stringify(data, null, 2) in JavaScript or json.dumps(data, indent=2) in Python.

Is JSON case-sensitive?

Yes. "City" and "city" are different names, and the literals must be lowercase: True, NULL, and FALSE are all invalid.

What is the JSON MIME type and file extension?

The registered media type is application/json, and files use the .json extension. APIs send the media type in the Content-Type header so clients know how to read the body.

Does JSON have to start with { or [?

No. Since RFC 7159 in 2014, a JSON document can be any single value, including a string, number, true, false, or null. Some older parsers and many APIs still expect an object or array at the top.

Is there a maximum size for JSON?

The format sets no limit on document size, nesting depth, string length, or number size. Parsers, servers, and databases each impose their own, so check the limits of whatever receives your data.

Is JSON the same as a JavaScript object?

No. JSON is text with a stricter grammar that borrows JavaScript’s literal syntax. A JavaScript object can hold functions, undefined, and single-quoted strings; JSON text cannot. JSON.parse turns the text into an object and JSON.stringify turns an object back into text.

Who created JSON?

Douglas Crockford specified and popularized it in the early 2000s, based on a subset of JavaScript. It is now standardized as ECMA-404 and IETF RFC 8259, which agree on the grammar.