tidyr::fill
fill(data, ..., .by = NULL, .direction = c("down", "up", "downup", "updown")) Returns:
data.frame · Updated April 4, 2026 · Tidyverse tidyr tidyverse missing-values data-wrangling
fill() replaces NA values in selected columns with the nearest non-NA value in a chosen direction. It’s the standard fix for data in “stacked” format where a value appears once and is left blank until it changes.
Signature
fill(data, ..., .by = NULL, .direction = c("down", "up", "downup", "updown"))
Parameters
| Parameter | Type | Description |
|---|---|---|
data | data.frame | Input data frame or tibble |
... | tidy-select | Columns to fill. Accepts tidyr::ends_with(), starts_with(), everything(), etc. |
.by | tidy-expr | Group by columns — fill operates within each group, not crossing boundaries |
.direction | string | Direction: "down" (default), "up", "downup", or "updown" |
Direction
The .direction argument controls which non-NA value fills the gap:
# Default: propagate the previous value downward (LOCF — last observation carried forward)
df <- tibble(
quarter = c("Q1", "Q2", "Q3", "Q4", "Q1", "Q2"),
year = c("2000", NA, NA, NA, "2001", NA),
sales = c(66013, 69182, 53175, 21001, 46036, 58842)
)
df |> fill(year)
# # A tibble: 6 × 3
# quarter year sales
# <chr> <chr> <dbl>
# 1 Q1 2000 66013
# 2 Q2 2000 69182
# 3 Q3 2000 53175
# 4 Q4 2000 21001
# 5 Q1 2001 46036
# 6 Q2 2001 58842
# Fill upward — propagate the next value upward (NOCB — next observation carried backward)
df |> fill(year, .direction = "up")
# Fill down first, then fill remaining NAs upward
df |> fill(year, .direction = "downup")
# Fill up first, then fill remaining NAs downward
df |> fill(year, .direction = "updown")
Filling by Group
The .by argument fills within groups without permanently grouping the data. This is cleaner than using dplyr::group_by() because you don’t need to ungroup afterward:
library(tidyr)
library(dplyr)
df <- tibble(
group = c("A", "A", "A", "B", "B", "B"),
x = c(1, NA, NA, 2, NA, NA),
y = c("p", NA, "r", "q", NA, "s")
)
df
# # A tibble: 6 × 3
# group x y
# <chr> <dbl> <chr>
# 1 A 1 p
# 2 A NA NA
# 3 A NA r
# 4 B 2 q
# 5 B NA NA
# 6 B NA s
df |> fill(x, y, .by = group)
# # A tibble: 6 × 3
# group x y
# <chr> <dbl> <chr>
# 1 A 1 p
# 2 A 1 p
# 3 A 1 r
# 4 B 2 q
# 5 B 2 q
# 6 B 2 s
Without .by, the fill would cross group boundaries.
Filling All Columns
Use everything() to fill every column with NAs at once:
df <- tibble(
x = c(1, NA, 3),
y = c("a", NA, "c"),
z = c(TRUE, NA, FALSE)
)
df |> fill(everything(), .direction = "down")
# # A tibble: 3 × 3
# x y z
# <dbl> <chr> <lgl>
# 1 1 a TRUE
# 2 1 a TRUE
# 3 3 c FALSE
Chaining Directions for Complex Patterns
If you need trailing NAs filled too, chain fill() calls:
df <- tibble(
id = c(1, 1, 1, 1),
value = c("a", NA, NA, NA)
)
# Chain down then up to fill both leading and trailing NAs
df |>
fill(value, .direction = "down") |>
fill(value, .direction = "up")
# # A tibble: 4 × 2
# id value
# <dbl> <chr>
# 1 1 a
# 2 1 a
# 3 1 a
# 4 1 a <- trailing NA also filled
This is equivalent to .direction = "downup".
See Also
- tidyr::pivot_longer() — reshape wide data to long format, often a precursor to filling
- tidyr::replace_na() — replace NAs with a fixed value instead of adjacent values
- tidyr::separate() — split a single column into multiple columns