A JSON array is an ordered list of values, written between square brackets with a comma between each value. The values can be strings, numbers, booleans, null, objects or other arrays, and one array may mix them. Arrays matter because almost every API uses them to send lists, such as search results, order lines, tags or map coordinates. The key rule is that the order of the items is part of the data, so every parser returns the items in the order they were written.
This page starts with the grammar of an array and the shapes of arrays found in real API responses. Next come the syntax mistakes that break an array, with the errors Node.js 22 prints for them. We then read, loop over and change arrays in JavaScript without the classic traps. The last part covers design choices for arrays in REST APIs. Objects, the other half of JSON, have their own page on JSON objects.
1. The Grammar of a JSON Array
RFC 8259, the standard that defines JSON, describes an array in a single line: square brackets around zero or more values, with commas between the values. Spaces, tabs and line breaks are allowed around the brackets and commas. A parser therefore returns the same array for a one-line version and an indented version.
[
"admin",
"editor",
"contributor"
]
Three practical rules follow from that grammar. The syntax diagram below traces them as paths: any route from left to right produces a valid array, and anything that leaves the lines is an error.
- An array can be empty. The text [] is a complete, valid array.
- Every comma must sit between two values. A comma right after the opening bracket or right before the closing bracket has a value on one side only, so the array is invalid.
- The values do not need to share a type. The standard sets no type rule for items, so [1, “two”, true, null] is valid JSON.

1.1. Order Is Part of the Data
RFC 8259 calls an array an ordered sequence of values (section 1). An object, in contrast, is an unordered collection. If a server sends [“gold”, “silver”, “bronze”], every client reads “gold” at position 0. Positions start at 0, so the last index is the length minus 1. Array items can be any of the JSON data types, including objects and other arrays.
2. Array Shapes Found in API Responses
Real APIs reuse a few array shapes. Once we recognize the shape, we know what each position means.
2.1. A List of Simple Values
The plainest array holds strings or numbers, such as the access rights of a user or a set of tags. Each item stands on its own, and its position often carries no special meaning.
{
"name": "Admin",
"age": 36,
"rights": ["admin", "editor", "contributor"]
}
2.2. An Array of Objects
The most common shape in REST APIs is an array of objects. A collection endpoint such as GET /products returns one object per resource, and every object has the same fields. The code examples in section 4 use this response.
{
"items": [
{"id": 101, "title": "Keyboard", "price": 45.5, "inStock": true},
{"id": 102, "title": "Monitor", "price": 189.0, "inStock": false},
{"id": 103, "title": "Mouse", "price": 19.99, "inStock": true}
]
}
2.3. Arrays Inside Arrays
An array whose items are arrays is called a nested or multi-dimensional array. It suits table rows and coordinates. GeoJSON, the standard JSON format for map data, writes each point as an array of numbers with longitude first and latitude second. A point in central London looks like this:
{
"type": "Point",
"coordinates": [-0.1276, 51.5072]
}
Nothing in the array says which number is which. Only the position tells us, so swapping the two numbers moves the point from London to the Indian Ocean near the equator.
2.4. An Array as the Whole Document
A JSON document does not have to start with an object. The first JSON RFC allowed only an object or an array at the top level. RFC 7159 relaxed that rule in 2014, and RFC 8259 keeps it: any value can be a complete JSON text (section 2). A body that contains only [1, 2, 3] is valid JSON. Section 6.1 explains why many APIs still wrap their lists in an object.
3. Syntax Mistakes That Break an Array
Most broken arrays come from writing JSON by hand or gluing strings together. For five broken arrays and two valid ones, JSON.parse() in Node.js 22 prints:
["admin", "editor",] -> SyntaxError: Unexpected token ']', "["admin", "editor",]" is not valid JSON
["admin" "editor"] -> SyntaxError: Expected ',' or ']' after array element in JSON at position 9 (line 1 column 10)
[1,,3] -> SyntaxError: Unexpected token ',', "[1,,3]" is not valid JSON
['admin'] -> SyntaxError: Unexpected token ''', "['admin']" is not valid JSON
[NaN] -> SyntaxError: Unexpected token 'N', "[NaN]" is not valid JSON
[] -> []
[1, "two", true, null, {"n": 5}, [6]] -> [1,"two",true,null,{"n":5},[6]]
The messages vary in style, but each one names the character where the parser stopped, and that character is the first place to look in the text.
| Broken text | What is wrong | Fix |
|---|---|---|
| [“admin”, “editor”,] | A trailing comma before the closing bracket | Remove the last comma. |
| [“admin” “editor”] | A missing comma between two values | Add the comma. |
| [1,,3] | An empty slot between two commas | Write null if a placeholder is needed. |
| [‘admin’] | Single quotes around a string | Use double quotes. |
| [NaN] | NaN, Infinity and undefined are not JSON values | Send null or a real number instead. |
One habit prevents all five errors: never assemble JSON from string pieces. Build a real array in our language and let the serializer write the text, for example with JSON.stringify(), which cannot produce these mistakes.
Copying from JavaScript source is another common cause. JavaScript code accepts a trailing comma and single quotes in an array. A sample taken from a .js file can therefore look right and still fail as JSON. The JSON syntax page lists the other differences.
4. Reading and Changing a JSON Array in JavaScript
The method JSON.parse() turns array text into a regular JavaScript Array, so every built-in array method works on the result. Let’s parse the user document from section 2.1 and inspect its rights.
const body = '{"name": "Admin", "rights": ["admin", "editor", "contributor"]}';
const user = JSON.parse(body);
console.log(Array.isArray(user.rights));
console.log(typeof user.rights);
console.log(user.rights.length);
console.log(user.rights[0]);
console.log(user.rights[5]);
console.log(user.rights.at(-1));
true
object
3
admin
undefined
contributor
Look at the second line of output. The typeof operator reports “object” for arrays, so it cannot tell an array from an object. The method Array.isArray() can, and it is the right check before looping over data from an outside source. Reading an index that does not exist returns undefined instead of throwing an error, and at(-1) reads from the end of the array.
4.1. Loop with for…of, Not for…in
Many older examples use a for…in loop, which is a common trap. A for…in loop walks over property names. On an array, it hands us the indexes as strings, and it would also pick up any extra property that some library added to the array. A for…of loop hands us the values in order, which is what we want almost every time.
const user = JSON.parse('{"rights": ["admin", "editor", "contributor"]}');
for (const i in user.rights) console.log(i, typeof i);
for (const right of user.rights) console.log(right);
0 string
1 string
2 string
admin
editor
contributor
The forEach() method also works. A classic counting loop with an index is useful only when the code needs the position as a number.
4.2. Filter, Map and Find an Array of Objects
The built-in array methods save the most code on arrays of objects. The method filter() keeps the items that pass a test, and map() turns each item into a new value. The method find() returns the first match, and reduce() combines all items into one value. None of them changes the original array.
const response = `{
"items": [
{"id": 101, "title": "Keyboard", "price": 45.5, "inStock": true},
{"id": 102, "title": "Monitor", "price": 189.0, "inStock": false},
{"id": 103, "title": "Mouse", "price": 19.99, "inStock": true}
]
}`;
const { items } = JSON.parse(response);
const available = items.filter(item => item.inStock);
console.log(available.map(item => item.title));
console.log(items.find(item => item.id === 102).price);
console.log(items.reduce((sum, item) => sum + item.price, 0));
[ 'Keyboard', 'Mouse' ]
189
254.49
The price 189.0 comes back as 189, because both texts describe the same JavaScript number. Adding decimal prices can also produce small rounding errors, which is why many APIs send money as whole cents or strings.
4.3. Remove Items with splice(), Not delete
To change an item, assign a new value to its index. To add an item at the end, call push(). To remove an item, use splice(). The delete operator looks as if it should work, but it only empties the slot. The array keeps its length, and the empty slot turns into null when the array is written back to JSON.
const a = JSON.parse('["admin", "editor", "contributor"]');
delete a[1];
console.log(a.length, JSON.stringify(a));
const b = JSON.parse('["admin", "editor", "contributor"]');
b.splice(1, 1);
console.log(b.length, JSON.stringify(b));
b.push("blogger");
b[0] = "owner";
console.log(JSON.stringify(b));
3 ["admin",null,"contributor"]
2 ["admin","contributor"]
["owner","contributor","blogger"]
The first output line shows the bug. A client that receives [“admin”,null,”contributor”] finds a null where a role used to be. The second line, built with splice(), is the result we wanted.
4.4. Walk a Nested Array
For an array of arrays, one loop handles the outer array and the code inside it deals with each row. Two index lookups in a row, such as users[1][2], read a single cell. The method flat() merges the inner arrays into one list when it does not matter which row a value came from.
const siteInfo = JSON.parse(`{
"name": "blogger",
"users": [
["admins", "1", "2", "3"],
["editors", "4", "5", "6"]
]
}`);
for (const row of siteInfo.users) {
const [role, ...ids] = row;
console.log(role, ids);
}
console.log(siteInfo.users[1][2]);
console.log(siteInfo.users.flat());
admins [ '1', '2', '3' ]
editors [ '4', '5', '6' ]
5
[ 'admins', '1', '2', '3', 'editors', '4', '5', '6' ]
The line const [role, …ids] = row is called destructuring. It puts the first item into role and the remaining items into ids. The destructuring works here because every row follows the same layout: the role name first, then the user ids.
5. JSON Arrays in Other Languages
Every JSON library maps a JSON array to the standard list type of its language: a list in Python, a List in Java and C#, and a slice in Go.
In Python 3, the json module turns each item into the matching Python type. It also writes a tuple as a JSON array, so a tuple comes back as a list after a round trip.
import json
data = json.loads('[1, "two", true, null, {"n": 5}, [6]]')
print(data)
print(type(data).__name__, [type(v).__name__ for v in data])
print(json.dumps((1, 2, 3)))
[1, 'two', True, None, {'n': 5}, [6]]
list ['int', 'str', 'bool', 'NoneType', 'dict', 'list']
[1, 2, 3]
In Java, Jackson needs a type hint to know what to build from an array. A TypeReference keeps the generic type, so the items arrive as strings in a List.
ObjectMapper mapper = new ObjectMapper();
List<String> rights = mapper.readValue(
"[\"admin\", \"editor\"]", new TypeReference<List<String>>() {});
6. Designing Arrays in a REST API
Valid syntax is not enough. Once clients depend on the way an API returns its lists, any change to that shape breaks them.
6.1. Wrap Collections in an Object
A top-level array is valid JSON, but it leaves no room to grow. If GET /products returns a bare array, there is nowhere to add a total count, a next-page link or a warning later without breaking clients. Wrapping the list in an object keeps that option open. The numbers in this example are made up:
{
"items": [
{"id": 101, "title": "Keyboard"},
{"id": 103, "title": "Mouse"}
],
"page": 1,
"pageSize": 20,
"total": 143
}
Our guide to pagination, sorting and filtering covers the paging fields that APIs add next to the list.
6.2. Send an Empty Array, Not null
When a collection has no items, return [] rather than null or a missing field. A client can loop over an empty array with no extra checks. With null, every client must check the value first, because a for…of loop over null throws TypeError: null is not iterable. Keep null for values that are truly unknown, and document the difference.
6.3. Keep Items the Same Shape
JSON allows mixed types in an array, but mixed arrays are hard for clients to use. Typed languages such as Java and C# expect one element type per list. An array where every item has the same type and the same fields is simpler to document, validate and map to classes. JSON Schema can enforce this with the items keyword, and minItems and uniqueItems add rules about size and duplicates.
6.4. Limit the Size of Large Arrays
The method JSON.parse() reads the whole text before our code sees a single item. RFC 8259 also allows parsers to limit text size and nesting depth (section 9). For long lists, send pages instead of one huge array. For logs and exports, JSON Lines puts one value on each line.
7. JSON Array FAQ
Two questions about JSON arrays come up in searches again and again.
7.1. How Do I Convert a JSON Array to a JavaScript Array?
Call JSON.parse() on the text. The result is already a real JavaScript Array, so no extra conversion step is needed. When the text comes from fetch(), response.json() does the parsing for us, as the JSON with Ajax page shows.
7.2. How Do I Check That a Value Is an Array?
Use Array.isArray(value). The typeof operator returns “object” for arrays, as the output in section 4 shows, so it cannot make that distinction.
8. Conclusion
A JSON array is a bracketed, comma-separated list whose order is part of its meaning. Let a serializer write it so the syntax stays clean, read it with for…of and the array methods, and remove items with splice() rather than delete. In an API, wrap lists in an object, send [] when there are no items, and keep the items the same shape. To pull values out of large nested arrays, the JSONPath page shows a query language built for that job.
9. References
These standards and documentation pages support the rules and the behavior shown on this page.
- RFC 8259, section 5: Arrays
- RFC 7946, section 3.1.1: GeoJSON positions
- MDN: Array
- MDN: Array.isArray()
- MDN: for…in
- MDN: Array.prototype.splice()
- Python: json module
- JSON Schema: array reference
Happy Learning !!
Comments