tibble as_tibble() in R: Convert Objects to Tibbles
The as_tibble() function in the tibble package converts an existing data frame, list, matrix, or named vector into a tibble, with optional rownames handling and stricter name repair than base coercion.
as_tibble(mtcars) # data.frame to tibble as_tibble(mtcars, rownames = "car") # keep row names as column as_tibble(list(x = 1:3, y = c("a","b","c"))) # named list to tibble as_tibble(matrix(1:6, 2, 3)) # matrix to tibble as_tibble(c(a = 1, b = 2, c = 3)) # named vector (use enframe) as_tibble(df, .name_repair = "unique") # auto-fix duplicate names as_tibble(df, .name_repair = "minimal") # keep names as-is
Need explanation? Read on for examples and pitfalls.
What as_tibble() does in one sentence
as_tibble() converts an existing object into a tibble. You pass a data frame, named list, matrix, or another tibble, and the function returns a tbl_df with the same data, optional row-name handling, and stricter checks on column names than as.data.frame(). It is the standard coercion function in the tidyverse and the entry point for promoting base-R objects into modern pipelines.
The use case is straightforward. You read a CSV with read.csv(), run a base function that returns a data.frame, or have a list of equal-length vectors. One call to as_tibble() and you can pipe straight into dplyr and ggplot2 with predictable printing, no row-name surprises, and no accidental string-to-factor conversion.
Syntax
as_tibble() is an S3 generic with methods for the common R container types. Each method honors the same control arguments: .rows, .name_repair, rownames, and validate.
The full signature for the data.frame method is:
as_tibble(x, ..., .rows = NULL, .name_repair = "check_unique",
rownames = NULL, validate = NULL)
xis the object to convert (data frame, list, matrix, table, or similar)..name_repaircontrols duplicate or empty names:"check_unique"(default, errors on duplicates),"unique"(auto-suffix),"minimal"(keep as-is),"universal"(also fix syntax).rownamescontrols row-name behavior:NULLdrops them silently (default for tibbles),NAdrops them with no warning, or a string keeps them as a new column with that name.validateis deprecated in favor of.name_repair.
The return value always has class c("tbl_df", "tbl", "data.frame").
rownames whenever the input has meaningful row labels. Built-in datasets like mtcars and USArrests carry car or state names as row names. Default coercion silently drops them. as_tibble(mtcars, rownames = "car") preserves them as a proper character column, ready for joining or plotting.Six common patterns
1. Convert a data.frame
Note that the name column comes out as <chr>, not factor, even though data.frame() may have stored it as a factor on older R versions. The coercion is a clean read of the underlying vectors.
2. Preserve row names as a column
Without rownames = "car" the labels would vanish on the way in. With it, every downstream dplyr or ggplot2 step can use car as a regular column.
3. Convert a named list
All vectors must have the same length (or length 1 for recycling). Unnamed list elements trigger an error unless you set .name_repair = "unique" or "minimal".
4. Convert a matrix
If the matrix has no dimnames, as_tibble() auto-generates V1, V2, ... or errors with the default "check_unique" repair. Set .name_repair = "unique" for matrices that arrive nameless.
5. Handle duplicate column names with .name_repair
The four repair levels trade strictness for convenience. "check_unique" is safest for code, "unique" is most ergonomic for messy imports, "minimal" is rare but useful when you must round-trip duplicate names.
6. Convert a named vector (use enframe)
as_tibble() on a bare vector returns a single-column tibble. For the more useful two-column "name, value" shape, reach for enframe() instead. Its inverse, deframe(), turns a two-column tibble back into a named vector.
as_tibble() vs as.data.frame() vs tibble()
The three coercion paths solve different problems. as_tibble() validates names, drops row names by default, and never auto-converts strings to factors. as.data.frame() is the base-R workhorse with permissive name handling. tibble() builds fresh from vectors rather than coercing an object.
| Behavior | as_tibble() |
as.data.frame() |
tibble() |
|---|---|---|---|
| Input | Existing object | Existing object | Bare vectors |
| Row names | Dropped or kept via rownames = |
Always preserved | None |
| Strings to factors | Never | Was default before R 4.0 | Never |
| Duplicate column names | Errors (default) | Mangled or suffixed | Errors |
| List input | Equal-length vectors only | More lenient | Not directly |
| Sequential column refs | N/A (no expressions) | N/A | Allowed |
Decision rule:
- Use
as_tibble()when you already have adata.frame,list, ormatrixand want a tibble. - Use
tibble()when you are building columns inline from raw vectors. - Use
as.data.frame()only when a downstream function explicitly demands the base class.
as_tibble() is a one-way door into the tidyverse. Once an object is a tibble, every dplyr verb, every ggplot2 mapping, and every tidyr pivot works without surprise. The function is small but it is the threshold that separates messy base-R objects from a clean, predictable pipeline.Common pitfalls
Pitfall 1: silently losing row names. Default coercion drops them. If they encode information (state names, gene IDs, time stamps), pass rownames = "your_column".
Pitfall 2: lists with unequal lengths. as_tibble() recycles length-1 only. Anything else raises a "Tibble columns must have compatible sizes" error.
The second call shows the standard fix: pad the short side with NA (or trim the long side) so all elements share a length.
.name_repair = "check_unique" errors on duplicates. This is a hard stop, not a warning. If your input source legitimately has duplicate names (a wide format with collision-prone variable codes, for example), set .name_repair = "unique" explicitly. Silent acceptance is intentionally unavailable to prevent ambiguous column references downstream.Pitfall 3: assuming as_tibble() works on every object. It only handles types with an S3 method: data.frame, list, matrix, table, and a few others. Custom classes need as.data.frame() first, then as_tibble().
Try it yourself
Try it: Convert the built-in airquality dataset to a tibble while preserving the original row numbers as a column called obs_id.
Click to reveal solution
Explanation: airquality uses default integer row names. Passing rownames = "obs_id" materializes them as a character column at the front of the tibble, so downstream joins and labels can use them directly.
Related tibble functions
After mastering as_tibble(), look at:
tibble(): build a tibble column-by-column from raw vectors.tribble(): build a tibble row-by-row, useful for fixed lookup tables.enframe(): convert a named vector into a two-column tibble.deframe(): the inverse, turn a two-column tibble back into a named vector.rownames_to_column()andcolumn_to_rownames(): round-trip row names through a column.is_tibble(): check whether an object is already a tibble.
For the full coercion reference, the official as_tibble() documentation lists every method, argument, and edge case.
FAQ
What is the difference between as_tibble() and tibble() in R?
as_tibble() converts an existing object (a data frame, list, matrix, or another tibble) into a tibble. tibble() builds a fresh tibble from raw vectors passed as named arguments. Use as_tibble() when you already have data in another container and want to enter the tidyverse. Use tibble() when you are constructing a small frame inline, especially when later columns depend on earlier ones. Both return identical tibble objects; only the input differs.
How do I keep row names when converting to a tibble?
Pass the rownames argument: as_tibble(mtcars, rownames = "car"). The argument value becomes the new column name. If you omit it, row names are silently dropped because tibbles do not carry row names by design. For built-in datasets like mtcars and USArrests where row names encode identity, always set rownames. To go the other way later, use column_to_rownames().
Why does as_tibble() error on duplicate column names?
The default .name_repair = "check_unique" rejects duplicates as a safety measure. Duplicate names make column references ambiguous in dplyr and tidyr. To accept duplicates, pass .name_repair = "unique" (auto-suffixes them as x...1, x...2) or "minimal" (keeps them as-is, only safe if you never reference by name). The error message tells you exactly which names collided.
Is as_tibble() faster than as.data.frame()?
For typical sizes (thousands to millions of rows) the difference is negligible because both functions are essentially pointer rewrites of the underlying columns, not data copies. as_tibble() does extra name validation, so on pathological inputs (tens of thousands of columns) it can be slower. For everyday work the choice should be about behavior (row-name handling, name repair, type preservation), not speed.
Can I convert a tibble back to a data.frame?
Yes, use as.data.frame(tbl). It drops the tibble class and re-creates row names as 1, 2, 3, .... You rarely need this because tibbles already inherit from data.frame, so any function expecting a data frame accepts a tibble directly. The one case to convert back is when you pass to a function that explicitly checks class(x) == "data.frame" or relies on partial column-name matching.