dplyr::arrange

arrange(.data, ..., .by_group = FALSE)
Returns: tibble | data.frame · Updated April 1, 2026 · Tidyverse
r dplyr tidyverse data-wrangling sorting

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

ParameterTypeDefaultDescription
.datatibble / data.frame / lazy frameRequiredA data frame, tibble, or lazy data frame from dbplyr/dtplyr
...data-maskingRequiredColumn names (or expressions) to sort by. Use desc(col) for descending
.by_grouplogicalFALSEIf 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