tidyr spread() in R: Long to Wide (Superseded by pivot_wider)
The spread() function in tidyr reshapes data from LONG to WIDE format. As of tidyr 1.0 (2019), it is SUPERSEDED by pivot_wider(); existing code works but new code should use pivot_wider.
df |> spread(key = "var", value = "val") # superseded df |> pivot_wider(names_from = var, values_from = val) # modern df |> gather(key, value, ...) # long form (also superseded) df |> pivot_longer(cols, names_to = ...) # modern long form
Need explanation? Read on for examples and pitfalls.
What spread() did in one sentence
spread(data, key, value) took a data frame in long format (a key column and a value column) and reshaped it to wide format with one column per key value. Since tidyr 1.0, it is superseded by the more flexible pivot_wider().
Migration
Replace spread(key = X, value = Y) with pivot_wider(names_from = X, values_from = Y).
pivot_wider() is more flexible than spread(): it supports multiple value columns, prefixes, and complex naming. For new code, always use pivot_wider.Five common patterns (legacy)
1. Standard spread
Modern: pivot_wider(names_from = var, values_from = val).
2. With fill for missing combinations
Modern: pivot_wider(names_from = var, values_from = val, values_fill = 0).
3. Unique combinations enforced
Modern: pivot_wider auto-handles types.
4. Multi-step pipeline
Modern: same with pivot_wider.
5. Verify both produce same result
spread() vs pivot_wider()
Same output for simple cases; pivot_wider is more flexible.
| Feature | spread() | pivot_wider() |
|---|---|---|
| Single value column | Yes | Yes |
| Multiple value columns | No | Yes |
| Custom naming | No | Yes (names_glue) |
| Prefix to new column names | No | Yes (names_prefix) |
| Status | Superseded | Recommended |
When to use which:
- pivot_wider for all new code.
- spread only in legacy code (no rewrites needed).
A practical migration
Search for spread( and replace with pivot_wider.
The argument names are explicitly named in pivot_wider (clearer in code review). spread used positional args.
Common pitfalls
Pitfall 1: ignoring the soft-deprecation. spread still works, but the tidyr team recommends migration. Future tidyr major versions may deprecate further.
Pitfall 2: confusing direction. spread is LONG -> WIDE. gather (also superseded) was WIDE -> LONG. Modern: pivot_wider and pivot_longer.
spread and gather were superseded in tidyr 1.0 (2019).* That's a long time. Most current tutorials and Stack Overflow answers show pivot_. Migrating saves time on future reading.Try it yourself
Try it: Reshape a long-format data frame to wide using BOTH spread and pivot_wider, then verify identical output. Save check to ex_check.
Click to reveal solution
Explanation: Both produce the same wide-format result for this simple case.
Related tidyr functions
After understanding spread's deprecation, look at:
pivot_wider(): modern replacementpivot_longer(): modern replacement for gathertidyr::gather(): also supersededdplyr::summarise()+pivot_wider: common pre-pivot aggregationdata.table::dcast(): alternative for big data
FAQ
Is spread deprecated in tidyr?
Superseded since tidyr 1.0 (2019). Use pivot_wider() instead.
What is the modern replacement for spread?
pivot_wider(names_from = key_col, values_from = value_col).
Why was spread superseded?
It couldn't spread multiple value columns at once and lacked features like custom naming. pivot_wider is a strict superset.
Will spread be removed?
Possibly in a future major tidyr version. Migrate proactively.
Are gather and spread both deprecated?
Both are superseded (not deprecated). Gather is replaced by pivot_longer; spread by pivot_wider.