Flatten
Expand nested JSON, struct, and list columns into flat columns. Explode a list into rows, split it into columns, or just count its items.
Flatten expands nested columns into separate flat columns. Struct, Object, and JSON-string columns are unnested into individual fields. List columns can be exploded into one row per element, split into a fixed number of indexed columns, or reduced to an item count, depending on the mode you choose. New columns are named using the pattern originalcolumn_fieldname. The source column can be kept or dropped. You can flatten all eligible columns at once or select specific columns.
Only columns with Object, List, or Struct data types appear in the Flatten operation. String, numerical, and datetime columns are not shown. If no eligible columns exist, an info toast appears and the operation closes automatically.
When to Use Flatten
- Unpack JSON metadata. Expand a
metadataJSON column into separatemetadata_source,metadata_channelcolumns for filtering. - Explode a list into rows. Convert an array-valued column into one row per value for counting or joining, when you genuinely need row-per-element granularity.
- Split a list into columns. Turn a fixed-shape list, like a top-3 ranking or a set of tags with a known maximum count, into indexed columns on the same row instead of multiplying rows.
- Count list items without exploding. Get "number of tags" or "number of line items" as a new integer column, with no row multiplication.
- Prepare for Group By. Flatten nested struct fields before applying Group By on extracted sub-fields.
- Normalize API response data. Expand deeply nested API payload columns into queryable flat fields.
- Fix Group By warning. Group By warns when Object or List columns exist. Flatten them first to avoid data loss in aggregations.
Sample Dataset
The examples in this doc use the Edilitics sample orders dataset. Download it to follow along in your own workspace.
edilitics_sample_orders.csv
Sample orders dataset for hands-on practice · 500 rows
Relevant columns for Flatten examples:
Prop
Type
List Modes
A List column supports three modes, chosen per column. Struct, Object, and JSON-string columns always unnest the same way, so no mode selector appears for them; only Max Depth applies.
Each element in the list becomes its own row. This multiplies row count: a 500-row dataset with an average list length of 3 produces approximately 1,500 rows after exploding.
Use this when you genuinely need one row per list element, such as splitting an order into one row per line item.
| order_id | tags |
|---|---|
| ORD-1 | ["sale", "priority"] |
| ORD-2 | ["standard"] |
After exploding tags:
| order_id | tags |
|---|---|
| ORD-1 | sale |
| ORD-1 | priority |
| ORD-2 | standard |
The list's elements become a fixed number of new indexed columns (tags_1, tags_2, ...) on the same row. Row count is unchanged.
You set the number of columns to create. A row with more elements than that number is rejected, not silently truncated, so no data is ever lost without your knowledge. If your data has longer lists than expected, increase the column count or switch to explode mode instead.
| order_id | tags |
|---|---|
| ORD-1 | ["sale", "priority"] |
| ORD-2 | ["standard"] |
After splitting tags into 3 columns:
| order_id | tags_1 | tags_2 | tags_3 |
|---|---|---|---|
| ORD-1 | sale | priority | (empty) |
| ORD-2 | standard | (empty) | (empty) |
The list column is replaced with a single integer column holding its element count. No new columns beyond that one, no row multiplication.
| order_id | tags |
|---|---|
| ORD-1 | ["sale", "priority"] |
| ORD-2 | ["standard"] |
After counting tags:
| order_id | tags_count |
|---|---|
| ORD-1 | 2 |
| ORD-2 | 1 |
How to Apply Flatten
Open the Flatten operation
In your Transform pipeline, click Add Operation and select Flatten from the operation list.
If no Object, List, or Struct columns exist, an info toast appears: "No columns with objects and lists found!" and the operation closes automatically.
Choose column selection mode
By default, Select All Columns is checked. All eligible nested columns are pre-loaded into the list with default settings.
Uncheck Select All Columns to switch to custom mode. In custom mode, start with one blank row and add more using Add Column.
Review or configure columns
For a Struct, Object, or JSON-string column:
| Field | Default | Description |
|---|---|---|
| Flatten Column | (all eligible columns in all-columns mode) | The nested column to flatten. |
| Max Depth | 3 | How many levels of nesting to recurse into. Options: 1, 2, 3, 4, 5. |
| Drop Original Column | On (toggled) | When on, the source column is removed after flattening. |
For a List column, Max Depth is replaced with a mode selector:
| Field | Default | Description |
|---|---|---|
| Flatten Column | (all eligible columns in all-columns mode) | The nested column to flatten. |
| Mode | Explode into rows | Explode into rows, split into columns, or count items. See List Modes above. |
| Number of columns | 5 | Only shown in Split into columns mode. Sets how many indexed columns to create. |
| Drop Original Column | On (toggled) | When on, the source column is removed after flattening. |
A warning line appears under a List row set to explode: "This multiplies row count: one new row per item in the list." A row set to Split into columns shows: "A row with more items than this will be rejected, not truncated."
Exclude columns (all-columns mode only)
In all-columns mode, click the remove icon next to any column to exclude it from flattening. Click the undo icon to re-include it. At least one column must remain included.
Add more columns (custom mode only)
Click Add Column to add another row. The button is disabled until the current row has a column selected and a valid configuration.
Click Save & Preview
Click Save & Preview. Edilitics flattens the selected columns and adds the new expanded columns to the dataset. The success toast confirms: "Flattening applied. Selected nested fields were expanded successfully."
Verify in the preview
Check the new columns. Struct fields appear as originalcolumn_fieldname. For List columns, check whether the mode you chose matches what you expected: explode increases row count, columns and count modes do not.
Before and After
Flatten metadata (Object column) with Max Depth 2, Drop Original Column on.
Input:
| order_id | revenue | metadata |
|---|---|---|
| ORD-2024-0001 | 12450.00 | {"source": "web", "channel": "organic"} |
| ORD-2024-0047 | 8320.50 | {"source": "mobile", "channel": "paid"} |
| ORD-2024-0099 | 83841.00 | {"source": "web", "channel": "direct"} |
Output:
| order_id | revenue | metadata_source | metadata_channel |
|---|---|---|---|
| ORD-2024-0001 | 12450.00 | web | organic |
| ORD-2024-0047 | 8320.50 | mobile | paid |
| ORD-2024-0099 | 83841.00 | web | direct |
Original metadata column dropped. Two new flat columns added. Row count unchanged.
How Flatten Works by Column Type
| Column type | What happens |
|---|---|
| Struct | Unnested using Polars unnest. Each field becomes a new column named originalcolumn_fieldname. |
| Object / JSON string | Parsed as JSON, converted to Struct, then unnested the same way. A value that fails to parse becomes null in the output rather than failing the whole column. |
| List | Depends on mode: exploded into new rows (default), split into a fixed number of indexed columns, or reduced to an item count. |
Flattening a List column in explode mode multiplies rows: one row per list element. A dataset with 500 rows where the list column averages 3 elements per row will produce approximately 1,500 rows after exploding. Use Split into columns or Count items instead if you want to keep the original row count. Check row count in the preview either way.
Max Depth
Max Depth applies to Struct, Object, and JSON-string columns. It controls how many levels of nesting the operation recurses into. Default is 3.
| Max Depth | Effect |
|---|---|
| 1 | Only the top-level fields of the struct are extracted. Nested structs within those fields remain nested. |
| 3 (default) | Recurses into 3 levels of nesting. Covers most real-world JSON payloads. |
| 5 | Maximum in the UI. Use for deeply nested API responses or complex Parquet schemas. |
New column names at each level append the field name: metadata_user_address_city at depth 3.
Code Equivalent
-- PostgreSQL: expand JSON object column
SELECT
order_id,
revenue,
metadata->>'source' AS metadata_source,
metadata->>'channel' AS metadata_channel
FROM orders;
-- BigQuery: flatten STRUCT column
SELECT
order_id,
revenue,
metadata.source AS metadata_source,
metadata.channel AS metadata_channel
FROM orders;import polars as pl
# Flatten struct/JSON column (dtype must be supplied explicitly)
df = df.with_columns(
pl.col("metadata").str.json_decode(pl.Struct({"source": pl.String, "channel": pl.String}))
).unnest("metadata").rename({
"source": "metadata_source",
"channel": "metadata_channel"
})
# Explode list column into rows
df = df.explode("tags")
# Split list column into indexed columns instead of exploding
df = df.with_columns(
pl.col("tags").list.to_struct(fields=["tags_1", "tags_2", "tags_3"])
).unnest("tags")
# Count list items without exploding
df = df.with_columns(pl.col("tags").list.len().alias("tags_count"))After Save & Preview, the pipeline shows a DQ delta badge on this step: green if the table score improved, red if it dropped. See Data Quality Scoring for how scores are calculated.
Operation Reference
Prop
Type
Frequently Asked Questions
Next Steps
Group By
Group by the new flat columns after expanding nested fields.
Filter
Filter rows by values in the newly expanded flat columns.
Drop / Rename Columns
Remove or rename flattened columns to clean up the schema after expanding.
Join
Join the flattened dataset with another table using the expanded key fields.
Need help? Email support@edilitics.com with your workspace, job ID, and context. We reply within one business day.
Last updated on
Window Functions
Apply rank, lag, lead, rolling and cumulative aggregations as new columns. Partition by any categorical column without writing code.
Code Editor
Write Python scripts directly inside your Transform pipeline. Polars 2.0, NumPy, SciPy, math, re, and Polars selectors preloaded. Test before saving. No imports required.