There is no official JSON style guide, but there are strong community conventions that make APIs predictable, maintainable, and pleasant to work with. Here are the most important ones.
Key naming: camelCase vs snake_case
The biggest debate in JSON API design. Both are widely used:
// camelCase — most common in JavaScript-centric APIs (GitHub, Twitter, Stripe)
{
"userId": 42,
"firstName": "Alice",
"createdAt": "2026-05-04T10:00:00Z"
}
// snake_case — common in Python-based APIs (Django REST Framework defaults)
{
"user_id": 42,
"first_name": "Alice",
"created_at": "2026-05-04T10:00:00Z"
}
Recommendation: Use camelCase for JSON APIs. It matches JavaScript variable naming natively, so JavaScript clients don't need to transform keys. If your backend is Python, use a serialization library that converts snake_case to camelCase at the API boundary (e.g., humps, Django REST Framework with a custom renderer).
Whatever you choose, be consistent. A mix of camelCase and snake_case in the same response is the worst outcome.
Always use double quotes
This is required by the JSON spec, not just a convention. Single quotes cause a parse error. Every key and every string value must use double quotes.
// Valid
{ "status": "active" }
// Invalid — will not parse
{ 'status': 'active' }
Use null for absent values — don't omit keys
When a value is not available, include the key with a null value rather than leaving the key out entirely:
// Preferred — consistent shape
{
"userId": 42,
"middleName": null,
"phoneNumber": null
}
// Avoid — clients must check both "key missing" and "key is null"
{
"userId": 42
}
Consistent key presence makes client-side code simpler. Consumers can access data.middleName safely and get null without first checking if the key exists.
Use ISO 8601 for dates and timestamps
ISO 8601 is unambiguous, sortable, and parseable in every major language:
{
"createdAt": "2026-05-04T14:30:00Z", // UTC timestamp
"updatedAt": "2026-05-04T14:30:00+05:30", // with timezone offset
"birthDate": "1995-08-22" // date only
}
Avoid Unix timestamps as strings ("created": "1746360600") — they're unreadable without conversion. Unix timestamps as numbers are acceptable for high-frequency logging where every byte counts, but name the field clearly (createdAtTimestamp).
Use arrays for ordered collections — not numbered keys
A common anti-pattern is using numbered keys to simulate an ordered list:
// Anti-pattern — don't do this
{
"item_0": { "name": "Widget A" },
"item_1": { "name": "Widget B" },
"item_2": { "name": "Widget C" }
}
// Correct — use an array
{
"items": [
{ "name": "Widget A" },
{ "name": "Widget B" },
{ "name": "Widget C" }
]
}
Arrays maintain order, have a length property, and can be iterated with standard array methods. Numbered object keys do none of this.
Avoid deeply nested structures
Nesting beyond 3-4 levels makes JSON hard to read and hard to access programmatically. If you find yourself writing data.response.user.profile.address.city, consider flattening:
// Overly nested
{
"response": {
"user": {
"profile": {
"address": { "city": "London" }
}
}
}
}
// Flatter — easier to work with
{
"user": {
"city": "London"
}
}
Pagination conventions
When returning paginated lists, include metadata that clients need to navigate pages:
{
"data": [ ... ],
"pagination": {
"page": 2,
"perPage": 20,
"total": 157,
"totalPages": 8,
"nextPage": 3,
"prevPage": 1
}
}
Alternatively, use cursor-based pagination for large or real-time datasets:
{
"data": [ ... ],
"cursor": {
"next": "eyJpZCI6MTAwfQ",
"hasMore": true
}
}
Validate your JSON structure
Use the JSON Validator to confirm your API responses are syntactically valid. For structural validation — ensuring required fields are present and have the correct types — consider JSON Schema validation. The JSON Formatter makes it easy to visually inspect complex nested responses.