tidyr unnest() in R: Flatten List Columns Into Rows
The unnest() function in tidyr flattens list-columns of tibbles into multiple rows, expanding each cell into its constituent rows. It is the opposite of nest().
df |> unnest(data) # flatten the data list column df |> unnest(c(col1, col2)) # multiple list cols df |> unnest(data, keep_empty = TRUE) # keep empty cells as NA rows df |> unnest_longer(col) # for vector list cols df |> unnest_wider(col) # spread named list cols to columns
Need explanation? Read on for examples and pitfalls.
What unnest() does in one sentence
unnest(data, cols) expands list-columns where each cell is a tibble (or vector) into multiple rows; other columns are duplicated. It reverses nest().
Syntax
unnest(data, cols, ..., keep_empty = FALSE, ptype = NULL, names_sep = NULL). cols are the list columns to unnest.
unnest() for tibbles in list columns; unnest_longer() for vectors; unnest_wider() for named lists turning into columns.Five common patterns
1. Round-trip with nest
2. Many-models extract
3. Keep empty cells
4. Multiple list columns
Both must have the same length per cell.
5. Nest then transform
unnest() family has 3 variants for different list-column shapes: tibbles, vectors, named lists. unnest = tibbles, unnest_longer = vectors, unnest_wider = named lists to columns. Pick by what's in the list column.unnest() vs unnest_longer() vs unnest_wider()
| Function | List column contains | Output |
|---|---|---|
unnest() |
Tibbles / data frames | Multiple rows |
unnest_longer() |
Atomic vectors | Multiple rows |
unnest_wider() |
Named lists | Multiple columns |
When to use which:
- unnest for nested data frames (most common after nest()).
- unnest_longer for vector list columns (e.g., from str_split).
- unnest_wider for named list columns (e.g., from JSON).
A practical workflow
The "many-models extract" pattern is unnest's most common use.
Per-group model coefficients in long format.
Common pitfalls
Pitfall 1: forgetting keep_empty. Empty list cells (length 0) are silently dropped. Use keep_empty = TRUE to preserve them as NA rows.
Pitfall 2: list column with mixed shapes. unnest expects each cell to be the same type (all tibbles or all vectors). Mixed types may error.
unnest() can produce HUGE output for large nested tibbles. A single nested tibble of 1M rows unnested becomes 1M output rows. Check sizes before running.Try it yourself
Try it: Nest mtcars by cyl, fit lm(mpg ~ wt) per group, then unnest the tidy coefficients. Save to ex_coef.
Click to reveal solution
Explanation: nest by cyl, fit lm, tidy each model, unnest the tidied coefficients.
Related tidyr functions
After mastering unnest, look at:
unnest_longer(): vectors to rowsunnest_wider(): named lists to columnsnest(): opposite (collapse to list column)hoist(): extract specific elements from list colspurrr::map(): per-cell transformation
FAQ
What does unnest do in tidyr?
unnest(data, cols) flattens list-columns where each cell is a tibble (or vector) into multiple rows. Reverses nest().
What is the difference between unnest and unnest_longer?
unnest expects each list cell to be a TIBBLE (data frame). unnest_longer expects each cell to be an atomic VECTOR. Different input shapes.
How do I keep empty list cells with unnest?
Pass keep_empty = TRUE. Empty cells become NA rows.
Does unnest preserve other columns?
Yes. Other columns are duplicated to match the unnested rows.
What is the difference between unnest and unite?
unnest expands list-columns into rows. unite combines multiple columns into one. Different operations.