dplyr rename() in R: Rename Columns Without Dropping
The rename() function in dplyr changes column names while keeping every column. Unlike select(), which drops columns you do not list, rename() only changes the names you specify.
rename(df, new_name = old_name) # rename one rename(df, mpg_kpl = mpg, hp_watts = hp) # rename many rename_with(df, toupper) # apply fn to all names rename_with(df, toupper, starts_with("m")) # selected names rename_with(df, ~ paste0("v_", .)) # lambda rename_with(df, ~ gsub("\\.", "_", .)) # replace chars rename(df, "new name" = old_name) # quoted for spaces
Need explanation? Read on for examples and pitfalls.
What rename() does in one sentence
rename() changes column names without dropping any column. You write new_name = old_name pairs; only the listed columns are renamed, every other column passes through unchanged. The order of columns is preserved.
Unlike select() (which DROPS columns you do not list), rename() is purely a renaming operation. Use select(df, new = old) ONLY when you want to rename AND drop other columns.
Syntax
rename() takes a data frame plus new = old pairs. Use bare names. Quote names with spaces or special characters using backticks or quotes.
The full signatures:
rename(.data, ...)
rename_with(.data, .fn, .cols = everything(), ...)
rename() for explicit pairs. rename_with() for function-based renaming across multiple columns (uses tidyselect for .cols).
rename(df, new = old) reads "old column becomes new column". This is the OPPOSITE direction from many languages where assignment goes left to right (old -> new). Mistakes here are common; if your rename does nothing, check the direction.Six common patterns
1. Rename one column
The new name on the left, old name on the right.
2. Rename multiple columns
List as many new = old pairs as you need. Order does not matter; the result preserves the data frame's original column order.
3. Apply function to all column names
rename_with() applies a function to existing names. Default scope is everything() (all columns).
4. Apply function to selected columns
The second argument selects columns via tidyselect. Only those names get the function applied.
5. Custom lambda with rename_with
The ~ paste0("v_", .) is shorthand for function(name) paste0("v_", name). The . is the original column name.
6. Replace pattern with regex
gsub() inside the lambda performs a regex replace on each column name. Useful for mass cleanup of imported data with dots, spaces, or punctuation in column names.
rename() is a pure metadata operation; the data does NOT change. Renaming a column is just relabeling. The vector of values, types, and order are all preserved. This is why rename() is essentially free in performance terms compared to mutate() (which evaluates expressions per row).rename() vs select() vs base R
Both rename() and select() can rename. The difference is whether other columns are kept.
| Task | rename() |
select() |
Base R |
|---|---|---|---|
| Rename one, keep rest | rename(df, new = old) |
(cannot do this directly) | names(df)[k] <- "new" |
| Rename + drop others | (does not drop) | select(df, new = old) |
df[, "old", drop=FALSE] then rename |
| Rename by function | rename_with(df, fn) |
(no equivalent) | names(df) <- fn(names(df)) |
| Rename many | rename(df, n1=o1, n2=o2) |
select(df, n1=o1, n2=o2) |
names(df)[match(c("o1","o2"), names(df))] <- c("n1","n2") |
When to use which:
- Use
rename()when you only want to change names, keep all columns. - Use
select()when you want to change names AND drop other columns. - Use
rename_with()for pattern-based renaming across many columns.
Common pitfalls
Pitfall 1: direction confusion. rename(df, mpg = mpg_old) renames mpg_old to mpg, not the other way. New name on the LEFT, old name on the RIGHT.
Pitfall 2: names with spaces or special chars. If the column is named "1st value" or "my var", you must quote: rename(df, new_name = \1st value\) (backticks) or rename(df, "new" = "1st value") (strings).
rename() errors if the OLD name does not exist. rename(mtcars, x = mpg_typo) errors because mpg_typo is not a column. To rename quietly when a column may or may not exist, use rename_with(df, ~ "x", any_of("mpg_typo")). any_of() ignores missing names.Pitfall 3: rename_with applies to ALL selected columns by default. rename_with(df, toupper) uppercases EVERY column name. To restrict, pass a tidyselect helper as the third argument: rename_with(df, toupper, where(is.numeric)).
Try it yourself
Try it: Take iris and use rename_with() to replace all dots in column names with underscores. Save to ex_iris and print the new names.
Click to reveal solution
Explanation: ~ gsub("\\.", "_", .) is a lambda that runs gsub() on each column name. The first argument is the regex pattern (a literal dot, escaped as \\.); the second is the replacement; the third is the input (each name in turn).
Related dplyr functions
After mastering rename(), look at:
select()withnew = old: rename AND drop other columnsrename_with(): function-based bulk renamingrelocate(): change column order without renamingsetNames()(base R): replace all names at once with a character vectorjanitor::clean_names(): opinionated cleanup of messy names (snake_case, no special chars)
For datasets with many columns named with weird patterns from external sources (Excel, SAS), reach for janitor::clean_names() first, then rename_with() for fine-tuning.
FAQ
What is the difference between rename and select in dplyr?
rename(df, new = old) keeps every column and only changes the listed names. select(df, new = old) keeps ONLY the columns you list (dropping all others) and renames them at the same time. Use rename() when you want to keep all columns; use select() when you also want to drop columns.
How do I rename multiple columns at once in dplyr?
Two options. List explicit pairs: rename(df, n1 = o1, n2 = o2, n3 = o3). Or use rename_with() with a function that maps old names to new: rename_with(df, ~ gsub("\\.", "_", .)) replaces all dots with underscores in every column name.
How do I rename columns with names that contain spaces?
Use backticks for column names with spaces: rename(df, new_name = \old name\). Or use strings: rename(df, "new_name" = "old name"). Either works; backticks are more idiomatic.
Can I rename a column conditionally in dplyr?
Use rename_with() with a tidyselect helper: rename_with(df, toupper, where(is.numeric)) uppercases only numeric column names. To rename only when a column exists, combine with any_of(): rename_with(df, ~ "new", any_of("maybe_old_name")).
Why does rename error with "column not found"?
The OLD column name in rename(df, new = old) must exist in the data frame. If you typo the old name or the data has different names than you expect, rename errors. Use rename_with(df, ~ "new", any_of("old")) for the silent version that ignores missing names.