tibble as_tibble_col() in R: Vector to One-Column Tibble
The as_tibble_col() function in the tibble package converts a vector into a one-column tibble. You pass any atomic vector or list and optionally a column name, and it returns a tbl_df with one column and as many rows as the input length.
as_tibble_col(1:5) # default column name "value" as_tibble_col(1:5, column_name = "x") # custom name as_tibble_col(letters[1:3], column_name = "letter") # character vector as_tibble_col(list(1:2, 3:4), column_name = "vals") # list-column as_tibble_col(c(1.1, 2.2), column_name = "price") # numeric column as_tibble_col(c(TRUE, FALSE, NA), column_name = "ok") # logical with NA 1:10 |> as_tibble_col("n") # pipe-friendly
Need explanation? Read on for examples and pitfalls.
What as_tibble_col() does in one sentence
as_tibble_col() lifts a single vector into a one-column tibble. You pass the vector and an optional column name, and the function returns a tbl_df with one column and length(x) rows. Unlike as_tibble_row() (its row-shaped twin), the output is always a column.
The use case is shape conversion: a model output, a sampling result, or a single column extracted from elsewhere needs to enter a tidyverse pipeline as a tibble. as_tibble_col() is the most direct constructor for that one column, with control over the column name and no extra metadata columns.
Syntax
as_tibble_col() has two arguments and a fixed contract. The input must be a vector (atomic or list), and the output is always a one-column tibble.
The full signature is:
as_tibble_col(x, column_name = "value")
xis any atomic vector or list. Length is preserved as the row count.column_nameis the name of the single output column. Defaults to"value".
The result always has exactly one column and class(c("tbl_df", "tbl", "data.frame")). Vector type carries through: a <dbl> vector produces a <dbl> column, a <chr> vector a <chr> column.
column_name explicitly. The default "value" is fine for one-off work but collides quickly when joining or binding multiple one-column tibbles. Naming the column at construction time, as_tibble_col(x, "price"), prevents a downstream rename() and makes the tibble self-documenting when printed.Five common patterns
1. Default conversion with a custom name
The vector length becomes the row count, the type carries through, and the chosen column_name labels the single column. This is the canonical pattern when a function returns a bare vector but a downstream tidyverse step expects a tibble.
2. Character vector with explicit name
Character vectors produce <chr> columns. The same call shape works for factors, dates, and logicals. No coercion happens, so timezone and factor levels survive the conversion.
3. List input creates a list-column
When the input is a list, the output column is a list-column. Each element becomes one cell, so the row count equals the list length, not the total element count. Pair with tidyr::unnest() to expand the list-column into long form.
4. Pipe-friendly inside a pipeline
as_tibble_col() accepts the piped input as its first argument and the column name as a positional second argument. This makes it a clean entry point into a pipeline that started with a bare numeric or character vector.
5. Pair with bind_cols to assemble a frame
When several independent functions each return a vector, lift each to a tibble and bind them column-wise. In practice tibble(id = 101:105, score = c(78, 91, 64, 88, 73)) is shorter, but the as_tibble_col() approach scales when the vectors come from different sources and must be combined dynamically.
as_tibble_col() vs enframe() vs tibble()
The three constructors all produce small tibbles but differ in column count and required input. as_tibble_col() always emits one column. enframe() emits two columns (name, value). tibble() builds from any number of named arguments.
| Behavior | as_tibble_col() |
enframe() |
tibble() |
|---|---|---|---|
| Input | Any vector or list | Vector (names optional) | Bare named arguments |
| Columns in output | Always 1 | Always 2 (name, value) | One per argument |
| Names of input used? | Discarded | Promoted to name column |
From argument names |
| Row count | length(x) |
length(x) |
Length of longest input |
| Typical use | Shape lift, one column | Name-value lookup, frequency tables | Inline multi-column build |
Decision rule:
- Reach for
as_tibble_col()when you have one vector and want one column. - Reach for
enframe()when a named vector should become a two-column key-value tibble. - Reach for
tibble()when several parallel vectors should sit side by side.
as_tibble_col() and as_tibble_row() are mirror images. Given the same input c(a = 1, b = 2, c = 3), the row variant produces 1 row by 3 columns, and the col variant produces 3 rows by 1 column. Internalize that duality and you stop confusing them: pick row() when each element is a column, pick col() when each element is a row of one column.Common pitfalls
Pitfall 1: input names are silently dropped. If you pass a named vector, the names disappear; as_tibble_col() keeps only the values.
If the names carry meaning, enframe() is the right function. as_tibble_col() is for vectors where the position is all that matters.
Pitfall 2: passing a data.frame errors. The function is strict; it expects a vector or list, not an already-rectangular object.
Use df$column or dplyr::pull(df, column) to extract a single column first, then lift it with as_tibble_col(). For multi-column conversion, use as_tibble().
column_name carefully when joining downstream. If two tibbles built with the default "value" get joined, the join key collides and either fails or auto-suffixes to value.x and value.y. Always pass an explicit column_name matching the role of the data ("price", "score", "code") so the column is ready for joins and pivots.Pitfall 3: list with length-mismatched elements works, atomic vector with mixed types coerces. A list-column tolerates ragged elements, but if you pass an atomic vector built with c(), R coerces silently.
The coercion to <chr> is c()'s doing, not as_tibble_col()'s. The function itself does not coerce; it inherits whatever type the input already has.
Try it yourself
Try it: Take the mpg column from mtcars, lift it into a one-column tibble named mileage, then add a second column band that labels each value as "low", "mid", or "high" based on whether it is under 15, 15 to 25, or above 25. Save the result to ex_bands.
Click to reveal solution
Explanation: as_tibble_col() does the shape lift from the bare numeric vector returned by mtcars$mpg into a tibble. After that, standard column-add syntax appends the classification, demonstrating how as_tibble_col() plugs cleanly into downstream tidyverse-or-base assembly.
Related tibble functions
After mastering as_tibble_col(), look at:
as_tibble_row(): the row-shaped twin, turns a named vector into a one-row tibble where each element becomes a column.enframe(): turn a named vector into a two-column tibble withnameandvaluecolumns, preserving the names.tibble(): build a tibble inline from raw named vectors of any length.as_tibble(): coerce an existing data.frame, list, or matrix into a tibble.tibble::deframe(): the inverse ofenframe(), collapses a two-column tibble back to a named vector.dplyr::pull(): extract a single column from a tibble as a bare vector, often the input toas_tibble_col().
For the full API, the official as_tibble_col() documentation lists every method and option.
FAQ
What is the difference between as_tibble_col() and enframe() in R?
as_tibble_col() produces a one-column tibble and discards any names on the input vector. enframe() produces a two-column tibble with name and value columns, promoting the input vector's names into the first column. Reach for as_tibble_col() when only the values matter and you want a clean single column. Reach for enframe() when the names carry meaning, such as a named result from table() or a lookup vector where each entry is a key-value pair.
Why does as_tibble_col() drop the names of my input vector?
The function is designed for shape lifting, not for preserving metadata. Its single column holds values, not labels; if names were kept, they would have nowhere to live. If you need them, use enframe() instead, which writes the names into a dedicated name column. You can also bind them back manually with tibble(name = names(x), value = x), but enframe() is the idiomatic way.
Can I use as_tibble_col() inside a pipeline?
Yes. The function takes the vector as its first argument, so it composes naturally with |> and %>%: rnorm(10) |> as_tibble_col("z"). Pair it with dplyr::mutate() or tidyr::pivot_* afterwards to enrich the column or reshape further. This is the most common production pattern: pull a vector from somewhere, lift it, then continue the pipeline.
How is as_tibble_col() different from tibble()?
tibble() builds from named arguments, one per column: tibble(x = 1:3, y = 4:6). as_tibble_col() lifts one existing vector into one column: as_tibble_col(1:3, "x"). Use as_tibble_col() for a single dynamic vector. Use tibble() when several parallel vectors and their names are known statically.
Can as_tibble_col() create a list-column?
Yes. Pass a list rather than an atomic vector, and the function produces a list-column where each list element becomes one cell. as_tibble_col(list(1:2, 3:4), "groups") creates a 2-row tibble with one list-column holding the vectors. Useful when each row carries a nested object such as a sub-sample or smaller tibble.