# Import JSON Files

VisiGrid reads JSON through an [import recipe](https://docs.visigrid.app/guide/import-recipes/): a `.json` export from an API or a download, or a JSON Lines file (`.jsonl`, `.ndjson`) with one record on each line. Each record becomes a row of a Table, and **Refresh** reads the next export the same way. JSON sources start in **VisiGrid 0.51.0**.

:::note
From **0.52.0**, **File → Open** on a JSON export opens the recipe builder on it. In 0.51.0, File → Open reports *Unknown file type: json*: use **Data → New Import Recipe…** instead.
:::

## Try it with a sample

Download the sample export and its recipe into the same folder (or right-click a link and choose **Save Link As…**):

- <a href="/samples/shop-orders.json" download><code>shop-orders.json</code></a>: eight orders from a fictional shop, as an e-commerce API might return them. The orders sit under an `orders` key, next to a `page` object and a smaller `refunds` list. Each order has a nested `customer` (one has no address), an `id` too large for a spreadsheet number, a `null` discount code, `true`/`false` flags and a list of `items`.
- <a href="/samples/shop-orders.recipe.toml" download><code>shop-orders.recipe.toml</code></a>: reads the `orders`, makes `created_at` a date, and keeps the paid orders.

Open `shop-orders.recipe.toml` with `Ctrl+O`. VisiGrid asks once before reading the file, then loads the Table:

![The shop_orders Table: 6 paid orders with id, number, created_at, status, customer.name, customer.email, customer.address.city, customer.address.country, total, currency, discount_code, gift and items columns](../../../assets/guide/json-recipe-table.png)

- **Nested objects became dotted columns**: `customer.name`, `customer.address.city`. Columns come in the order they first appear in the file.
- **The order with no address** (LL-1044) is empty in the two address columns.
- **`id` is text**: these IDs are larger than 9,007,199,254,740,992, so as numbers their last digits would change. VisiGrid keeps the column as text with every digit.
- **`total` is a number column**, because every value in it is a JSON number.
- **`gift` shows `TRUE`/`FALSE`**, the `null` discount codes are empty, and each `items` list is kept as its JSON text in one cell.
- The two orders that aren't paid were removed by the recipe's filter step.

## Make a recipe from your own export

1. **Data → New Import Recipe…**, and choose your `.json`, `.jsonl` or `.ndjson` file. From 0.52.0, **File → Open** on the file does the same.
2. The builder opens. On the left, **Records at** shows where the records are. VisiGrid finds them itself: the array at the top of the file, or else the largest array of records inside it. The recipe saves that path, so next month's export reads the same records even if another array grows larger. Press `Enter` on **Records at** to choose a different array.
3. Add steps as for any recipe. Dates in JSON are text, so a **Set types** step (`date:ymd` for `2026-09-01`) makes them dates. Numbers sent as strings, like `"10.50"`, need **Set types** too. From 0.52.0 you can click the type under a column in the preview (`Text ›`) to change it: the builder adds the Set types step for you. Right-click goes back a type. Scroll the preview sideways (Shift+wheel with a mouse) to reach columns past its edge.
4. **Save and load into Table** (`Ctrl+Enter`).

This is the sample recipe in the builder. *Records at* is `orders`, one of the 2 arrays of records in the file, and the preview shows the result after the filter step:

![The import recipe builder for shop-orders.json: Source JSON, Records at orders, the 13 columns in the file, steps Read the file (8 rows), Set types created_at date:ymd, and Keep rows where status is paid (8 to 6 rows), with a preview of the 6 rows](../../../assets/guide/json-recipe-builder.png)

The sample recipe file is short:

```toml
version = 1

[source]
kind = "json"
path = "shop-orders.json"
records = "orders"

[[step]]
op = "types"
columns = { created_at = "date:ymd" }

[[step]]
op = "filter"
column = "status"
is = "="
value = "paid"
```

## Refresh next month

When the next export arrives, replace the file and click **Refresh** (`Alt+F5`). To pick up a new file name each month, set **Each refresh reads** to **Newest match**. Set it to **All matching files** to append every export in a folder, with a **Source file** column. See [Refresh next month](https://docs.visigrid.app/guide/import-recipes/#refresh-next-month).

The same recipe runs without the app, for a scheduled job:

```bash
vgrid recipe run shop-orders.recipe.toml -o shop-orders.csv
```

```
./shop-orders.json (5ffb295b2671c694): 8 source rows -> 6 rows x 13 columns, ok
1. Set types created_at: date:ymd [8 -> 8 rows, 0 ms]
2. Keep rows where status is paid [8 -> 6 rows, 0 ms]: removed 2 rows
```

## Details

How values come through, repeated keys, JSON Lines, and memory for large files are covered in [JSON files](https://docs.visigrid.app/guide/import-recipes/#json-files) in the import recipe guide.