JSON Best Practices
Any valid JSON parses; good JSON stays maintainable for years. The difference is a handful of conventions about naming, types and structure — cheap to adopt at the start, expensive to retrofit once clients depend on your format. These are the practices that consistently pay off.
Pick one key naming style and never deviate
{ "firstName": "Ada", "createdAt": "2026-07-22T09:30:00Z" } // camelCase
{ "first_name": "Ada", "created_at": "2026-07-22T09:30:00Z" } // snake_caseBoth are fine; mixing them is not. camelCase dominates JavaScript-centric APIs, snake_case is common in Python and Ruby ecosystems (Stripe and GitHub use it). Whichever you choose, apply it to every key, document it, and enforce it in code review. Avoid keys with spaces or punctuation — they force bracket access in most languages — and never encode data in key names ("user_1234": {…}); make it a value instead.
Dates are ISO 8601 strings, in UTC
"createdAt": "2026-07-22T09:30:00Z" ✓
"createdAt": 1784107800 △ meaning unclear: seconds? ms?
"createdAt": "07/22/26" ✕ ambiguousJSON has no date type, so pick the least ambiguous representation: ISO 8601 with an explicit UTC Z. It sorts lexicographically, every language parses it, and a human can read it in a log file at 3 a.m.
Money and precision-sensitive numbers
JSON numbers are typically parsed as floating point, and floats cannot represent values like 0.1 exactly. For money, use integer minor units ("amountCents": 1999) or a string ("amount": "19.99") — the convention payment APIs use. The same applies to 64-bit IDs: JavaScript loses precision above 2^53, which is why Twitter’s API famously ships id_str alongside id.
Decide what null means — and mean it
A field that is null, and a field that is absent, are different signals: “this has no value” versus “this wasn’t provided.” Pick a policy (a common one: PATCH requests treat null as “clear this field” and absence as “leave unchanged”) and apply it consistently. Avoid other sentinel values — empty strings standing in for null, or -1 meaning “unknown” — they always leak into display code eventually.
Keep structure shallow and lists uniform
Every nesting level is a hoop consumers jump through; two to three levels covers most data honestly. Prefer arrays of objects with identical shapes — uniform records are what CSV converters, table renderers and type generators (like the JSON to TypeScript tool) expect. If items in one array have wildly different keys, that is usually two lists wearing one name.
Format for the reader; sort for the diff
JSON that humans maintain belongs in version control formatted: 2-space indentation is the ecosystem default. Sorting keys alphabetically — the JSON Sorter does it recursively — gives files a canonical form, so diffs show real changes instead of reordering noise. Machine-to-machine payloads go the other way: minified, since whitespace is pure transfer cost.
Security and robustness basics
Always parse with a real parser — never eval() — and treat inbound JSON as untrusted input: enforce size limits, validate structure (JSON Schema formalizes this), and don’t assume fields exist just because they usually do. Duplicate keys are technically tolerated by parsers (last one wins) but are always a bug in the producer; the JSON Validator catches outright syntax problems, and consistent formatting makes the logical ones visible. For the syntax rules themselves, see How to Fix Common JSON Errors.