JSON Table Viewer, Explained
Read this to understand how a JSON array of objects becomes a flat table, how nested keys turn into dotted columns, and where the flattening quietly loses or reshapes your data.
What the tool does
JSON is a tree. A table is a grid. The JSON Table Viewer converts the first into the second so you can scan an API response the way you scan a spreadsheet: one row per record, one column per field, sortable and searchable.
Consider three users from an API:
[
{"id": 1, "name": "Ada", "role": "admin", "active": true},
{"id": 2, "name": "Bela", "role": "editor", "active": false},
{"id": 3, "name": "Cy", "role": "viewer", "active": true}
]
That becomes four columns (id, name, role, active) and three rows. The union of every key across every object defines the column set. If one object is missing a key, that cell is left empty rather than dropped.
The value on screen is not magic. Each object is one row. Each distinct key path is one column. The rest of this article is about what "key path" means once objects contain other objects.
When to use it, and when not
Reach for a table view when the JSON is a list of similar records: search results, log lines, rows from a database dumped to JSON, a paginated API page. These share a stable shape, so the columns line up and the table stays dense.
Avoid it when the JSON is a single deeply nested configuration object, or when records have wildly different shapes. If object one has 4 keys and object two has 40 completely different keys, the flattened table has 44 columns and mostly empty cells. A tree viewer serves that better.
If you paste an object instead of an array, the tool searches inside it and uses the first array of objects it finds. The common {"data": [...]} envelope from REST APIs works without you touching anything.
How flattening works
Flattening walks each object and produces a set of (path, value) pairs. The path is the chain of keys from the root to a leaf, joined with dots. A leaf is any value that is not itself an object.
Here each k_i is a key name and n is the nesting depth of that leaf. A top-level field like name has depth n = 1. A field like user.address.city has depth n = 3. The rule is recursive: descend into every nested object, appending its key to the running path, and stop when you hit a value that is a string, number, boolean, null, or array.
Arrays are the deliberate exception. An array of scalars such as [80, 443] is not expanded into columns. It is shown inline as its JSON text, [80,443], in a single cell. This keeps the column count finite. If arrays were flattened by index, a list of 500 items would create 500 columns, which defeats the purpose.
Because arrays are shown as inline JSON, an array of objects (like tags: [{"k":"env"}]) is not broken out into tags.0.k columns. You see the raw JSON text in the cell. If you need to explode an array into rows, restructure the JSON first so the array is the top-level list.
A worked example with nested objects
Two records, three depths
Paste this and reproduce the numbers below:
[
{
"id": 1,
"user": {"name": "Ada", "address": {"city": "Turin"}},
"roles": ["admin", "billing"],
"active": true
},
{
"id": 2,
"user": {"name": "Bela", "address": {"city": "Split"}},
"roles": ["viewer"],
"active": false
}
]
- Start at record one. The key
idhas a scalar value, so it becomes columnidwith value1. - The key
useris an object, so descend. Inside itnameis scalar: columnuser.name=Ada. - Still inside
user, the keyaddressis another object. Descend again.cityis scalar: columnuser.address.city=Turin, at depth n = 3. - The key
rolesholds an array of scalars. It is not expanded. Columnroles=["admin","billing"]shown as text. - The key
activeis a boolean: columnactive=true.
Record two follows the same walk. The final table has 5 columns and 2 rows:
| id | user.name | user.address.city | roles | active |
|---|---|---|---|---|
| 1 | Ada | Turin | ["admin","billing"] | true |
| 2 | Bela | Split | ["viewer"] | false |
Notice the count: 5 columns come from 5 leaf paths, not from the 3 top-level keys plus 1 array. The two nested user fields each earn their own column, and the array stays as one.
What controls the column count
The number of columns equals the number of distinct leaf paths across all records, not the number of keys in any single record. This matters when records disagree.
Suppose 100 records all have id and name, but only 12 of them include an optional meta.source field. The table then has 3 columns, and meta.source is filled in 12 rows and empty in the other 88. The column exists because at least one record produced that path.
The chart shows why uniform data is comfortable and ragged data is not. Three uniform fields give 3 columns. Add one optional field and you get 4. Two nesting levels on top add another. A mix of dissimilar records here reaches 12 columns, most of them sparse.
Reading and interpreting the table
Once flattened, three things are worth checking before you trust what you see.
Sort direction on mixed types. A column that mixes numbers and strings sorts by the tool's comparison rule, not by your intuition. If id holds 10 as a string in some rows and the number 10 in others, sorting can place "10" before "9" because string order compares character by character. Confirm the type before reading a sort as numeric.
Empty versus null versus missing. An empty cell can mean the key was absent, or present with value null. Both render as blank. If that distinction matters, search for the raw value in the source JSON rather than reading the table alone.
Search scope. Text search matches the displayed cell text. Because an array of scalars is shown as JSON like ["admin","billing"], searching admin finds it, but searching for a value inside a nested-object array works only if that JSON text contains the string.
Common mistakes
Most confusion traces back to expecting the table to expand something it deliberately keeps whole.
- Expecting arrays of objects to explode into rows
- They do not. One JSON record is always one row. An array inside a record stays inside that row's cell. To get one row per array element, make the array the top-level list.
- Pasting the whole API body without the list
- If your response is
{"data": [...], "meta": {...}}, the tool uses the first array of objects, which is usuallydata. If the array you want is not the first one found, extract it before pasting. - Reading a blank cell as zero
- Blank means absent or null, never
0. A numeric column with blanks is not a column of zeros. - Trusting CSV export of nested cells
- When you export to CSV, a cell holding
["admin","billing"]is written as that literal JSON string. Downstream tools will treat it as one text field, not a list.
Related tools
The table viewer is a reading tool. For editing and conversion, pair it with these:
To convert the flattened table back and forth with JSON, use the CSV ↔ JSON Converter. To edit or filter the CSV you export, open the CSV Viewer & Editor. To group and count records instead of listing them, the Pivot Table Maker aggregates a CSV. If the source started life as a spreadsheet, the Excel → CSV Converter gets you clean CSV first. To hide sensitive columns before sharing, run the Data Anonymizer. To turn a small result into documentation, the Markdown Table Generator produces an aligned block. For columnar files, the Parquet & Feather Preview peeks inside without Python.
Everything here runs in your browser. Your pasted JSON never leaves your device, so you can safely inspect an API response that contains real user data before deciding what to redact.
Frequently asked questions
Why is my nested field showing as raw JSON text instead of its own column?
Because it is inside an array. Only nested objects flatten into dotted columns. An array, even an array of objects, is shown as inline JSON in a single cell. Move the array to the top level if you need it split.
How deep does the dotted-column flattening go?
As deep as the objects nest. A leaf at depth 4, like a.b.c.d, produces a column named a.b.c.d. There is no fixed limit beyond the structure of your data.
My array is at the top of the response but nested under a key. Will it still work?
If the top level is an object, the tool uses the first array of objects it finds inside, so {"data": [...]} works. If the array you want is not the first one found, extract just that array before pasting.
Do empty cells mean the value is zero?
No. An empty cell means the key was missing or its value was null. A blank in a numeric column is not 0, and treating it as zero will skew any total you compute later.
Why does sorting a column of numbers look wrong?
The values may be stored as strings. String comparison is character by character, so "100" sorts before "9". Check the source type; if the numbers are quoted in the JSON, they sort as text.