dplyr::arrange
arrange(.data, ..., .by_group = FALSE) tibble | data.frame · Updated April 1, 2026 · Tidyverse arrange() sorts rows of a data frame or tibble by one or more column values. It is dplyr’s row-ordering verb, and like other dplyr functions it uses data masking so you refer to columns by their bare names.
Syntax
arrange(.data, ..., .by_group = FALSE)
The ... argument accepts column names to sort by. Sorting is ascending by default. Wrap a column in desc() to reverse the order. When multiple columns are supplied, ties are broken by the next column in the list, and the sort is stable (original row order is preserved for ties).
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
.data | tibble / data.frame / lazy frame | Required | A data frame, tibble, or lazy data frame from dbplyr/dtplyr |
... | data-masking | Required | Column names (or expressions) to sort by. Use desc(col) for descending |
.by_group | logical | FALSE | If TRUE, sorts by grouping variables first. Applies to grouped data frames only |
Examples
Sort ascending
library(dplyr)
df <- tibble(
name = c("Alice", "Bob", "Carol", "Dave"),
age = c(32, 28, 45, 28),
salary = c(55000, 48000, 62000, 52000)
)
arrange(df, age)
# # A tibble: 4 × 3
# name age salary
# <chr> <dbl> <dbl>
# 1 Bob 28 48000
# 2 Dave 28 52000
# 3 Alice 32 55000
# 4 Carol 45 62000
Bob and Dave both have age 28. Their relative order matches the original input because arrange() uses a stable sort.
Sort descending
arrange(df, desc(age))
# # A tibble: 4 × 3
# name age salary
# <chr> <dbl> <dbl>
# 1 Carol 45 62000
# 2 Alice 32 55000
# 3 Bob 28 48000
# 4 Dave 28 52000
Multiple columns
When the first column has ties, the second column breaks them:
arrange(df, age, name)
# # A tibble: 4 × 3
# name age salary
# <chr> <dbl> <dbl>
# 1 Bob 28 48000
# 2 Dave 28 52000
# 3 Alice 32 55000
# 4 Carol 45 62000
NA values always go to the end
This catches many R users off guard. Unlike base R’s sort(), arrange() always places NA rows at the bottom, even when you use desc():
df_na <- tibble(x = c(1, NA, 3, NA, 2))
arrange(df_na, x)
# # A tibble: 5 × 1
# x
# <dbl>
# 1 1
# 2 2
# 3 3
# 4 NA
# 5 NA
arrange(df_na, desc(x))
# # A tibble: 5 × 1
# x
# <dbl>
# 1 3
# 2 2
# 3 1
# 4 NA
# 5 NA
Grouped data frames
By default, arrange() ignores grouping. Use .by_group = TRUE to sort within groups:
df_grouped <- tibble(
dept = c("Sales", "Sales", "IT", "IT"),
name = c("Carol", "Alice", "Bob", "Dave"),
salary = c(62000, 55000, 48000, 52000)
) |>
group_by(dept)
arrange(df_grouped, name, .by_group = TRUE)
# # A tibble: 4 × 3
# # Groups: dept [2]
# dept name salary
# <chr> <chr> <dbl>
# 1 Sales Alice 55000
# 2 Sales Carol 62000
# 3 IT Bob 48000
# 4 IT Dave 52000
Key behaviours
Stable sort. When two rows have equal values, their original order is preserved. This matters when you chain multiple arrange() calls and want earlier sorts to act as a tiebreaker.
NA placement. NA values always sort to the end regardless of direction. There is no way to override this in the current dplyr API.
.by_group controls group precedence. Without it, grouping is largely ignored. With .by_group = TRUE, grouping variables are sorted first, then the remaining columns you specify.
See Also
- dplyr::filter() — subset rows by condition
- dplyr::mutate() — create or modify columns
- /cookbooks/how-to-sort-a-data-frame-by-column/ — sorting data frames in R