Written and maintained by CASRAI Editorial Board
Last updated
A pipe in R passes the result of one expression into the next call, so a sequence of steps reads left to right instead of inside out. R has two pipes: the native pipe |>, built into base R since version 4.1.0, and the magrittr pipe %>%, which comes from a package. x |> f(y) is parsed as f(x, y), and that single rule is the core of this guide.
Which pipe do you need? Version cheat sheet
The native pipe needs a minimum R version, and two of its features arrived later. Check R.version.string before choosing a pipe for a shared analysis script.
| Feature | First available in | Source |
|---|---|---|
Native pipe |> |
R 4.1.0 | R documentation, ?pipeOp |
Placeholder _ (must be a named argument) |
R 4.2.0 | Tidyverse blog, base R vs magrittr pipes |
_ as the head of an extraction chain (_$coef[[2]]) |
R 4.3.0 | Tidyverse blog; example in ?pipeOp |
magrittr pipe %>% |
Installed package (magrittr or tidyverse) |
magrittr site |
The R documentation warns that code using the native pipe “will not be parsed as intended (probably with an error) in earlier versions of R.”
What it is used for in research
Research analysis scripts are long chains of small operations: filter the rows, compute a summary, fit a model, draw a figure. Written as nested calls, the order of operations reads from the innermost call outward. A pipe writes the same chain in the order it runs, which makes each step easy to check, add or reorder. The R for Data Science style chapter makes the same point: pipes make it easy to add or rearrange steps.
That readability matters for computational reproducibility, because a collaborator or reviewer who re-runs your script has to follow it line by line. Pipelines typically sit just before a plotting or testing step such as a histogram in R, a scatterplot in R, a box plot in R or a Kruskal-Wallis test in R.
Install or access (official source only)
Native pipe |>
Nothing to install. The native pipe is part of base R from version 4.1.0 onward; the reference page is ?pipeOp in R, or “Forward Pipe Operator” in the base package documentation.
magrittr pipe %>%
The magrittr site gives these install routes:
# easiest: the whole tidyverse
install.packages("tidyverse")
# or just magrittr
install.packages("magrittr")
# development version
pak::pak("tidyverse/magrittr")
Step-by-step: write your first pipeline
- Confirm your R version is 4.1.0 or later. Run
R.version.string. If it is older, use the magrittr pipe or upgrade R. - Start with a call that has the data as its first argument. The pipe inserts the left-hand side as the first argument of the right-hand call:
mtcars |> head(2) # same as head(mtcars, 2) - Chain a second step. Each result becomes the first argument of the next call:
mtcars |> subset(cyl == 4) |> nrow() # same as nrow(subset(mtcars, cyl == 4)) - Send the value to a different argument with the placeholder. Name the argument and use
_(R 4.2.0 or later):mtcars |> subset(cyl == 4) |> lm(mpg ~ disp, data = _) - Or name the other arguments instead. Naming the arguments before the “one” the pipe fills works without a placeholder:
mtcars |> subset(cyl == 4) |> lm(formula = mpg ~ disp) - Pull a value out of the result. From R 4.3.0 the placeholder can start an extraction chain:
mtcars |> subset(cyl == 4) |> lm(formula = mpg ~ disp) |> _$coef[[2]] - Use an anonymous function when the placeholder does not fit. Wrap the function in parentheses and call it:
mtcars |> subset(cyl == 4) |> (\(d) lm(mpg ~ disp, data = d))()
For the magrittr pipe, x %>% f is equivalent to f(x), and x %>% f(y, z = .) equals f(y, z = x), with . as the placeholder. The magrittr site’s example pipes iris through subset(Sepal.Length > mean(Sepal.Length)) and then the exposition pipe %$% into cor(Sepal.Length, Sepal.Width), which returns 0.3361992.
Output and how to read it
A pipe does not change what the code computes; it only changes how it is written. R’s documentation states that pipe operations are implemented as syntax transformations, so x |> f(y) is parsed as f(x, y). To read a pipeline, replace each |> with “then” and mentally rebuild the nested call:
| Pipeline | Same as |
|---|---|
mtcars |> head() |
head(mtcars) |
mtcars |> head(2) |
head(mtcars, 2) |
mtcars |> subset(cyl == 4) |> nrow() |
nrow(subset(mtcars, cyl == 4)) |
Regular R evaluation rules still apply. The documentation shows that in stop() |> (function(...) {})() the call to stop() is never evaluated, because the function on the right does not use its argument. Piped expressions are evaluated only when the right-hand side first uses them.
For script style, R for Data Science recommends a space before |> and, typically, putting it last on a line, and cautions against very long pipes, say longer than 10 to 15 lines:
flights |>
group_by(tailnum) |>
summarize(delay = mean(arr_delay, na.rm = TRUE), n = n())
Troubleshooting
Why do I get a parse error on |>?
Your R is probably older than 4.1.0. Code using the native pipe is not parsed as intended in earlier versions. Upgrade R, or use %>% from magrittr.
Why does x |> f fail when x %>% f works?
The right-hand side of the native pipe must be a call. The tidyverse blog notes that %>% lets you drop the parentheses when a function has no other arguments, while |> always requires them. Write x |> f().
Why can’t I pipe into + or if?
Functions in the right-hand call may not be syntactically special, such as + or if.
Why does the _ placeholder not work?
- It needs R 4.2.0 or later.
- It must be passed as a named argument, for example
x |> f(1, y = _). - It can appear only once on the right-hand side.
- It cannot be sent to several arguments, and it cannot sit inside another function call.
- As the head of an extraction (
_$coef) it needs R 4.3.0 or later.
Why can’t I build a function with . |> f()?
magrittr lets a pipe that starts with . create a function. The tidyverse blog states this is not supported by the base pipe; use an anonymous function such as \(d) f(d) instead.
Alternatives: native pipe vs magrittr pipe
Both pipes do the same basic job. Use this table to translate between them.
| Idiom | magrittr %>% |
Native |> |
|---|---|---|
| Basic call | x %>% f(y) |
x |> f(y) |
| Function with no other arguments | x %>% f (parentheses optional) |
x |> f() (parentheses required) |
| Placeholder symbol | . |
_ (R 4.2.0 or later) |
| Placeholder rules | Can be used several times | Named argument only; once only; not inside another function |
| Create a function by starting with the placeholder | . %>% f |
Not supported |
| Start an extraction chain | mtcars %>% .$cyl |
_$cyl style heads need R 4.3.0 or later |
| Where it comes from | Package: install.packages("magrittr") or tidyverse |
Base R 4.1.0 or later |
R’s own documentation says the native pipe “is motivated by the pipe introduced in the magrittr package, but is more streamlined.”
FAQ
What is the pipe operator in R?
It is an operator that passes the value on its left into the call on its right. Base R’s version is |> (R 4.1.0 or later), and the magrittr package provides %>%.
What is the difference between |> and %>%?
The native pipe always needs parentheses on the right-hand function, uses a named-argument _ placeholder (R 4.2.0 or later) usable once, and cannot create functions from a leading placeholder. The magrittr pipe allows x %>% f, uses ., and allows several uses of the placeholder.
Do I need to install a package to use |>?
No. It is part of base R from version 4.1.0.
How do I send the piped value to an argument other than the first?
Use the placeholder with a named argument, as in lm(mpg ~ disp, data = _), or name the other arguments so the piped value fills the remaining first position.
Sources
- R Core Team, “Forward Pipe Operator” (
?pipeOp), base package documentation for R 4.6.0: https://stat.ethz.ch/R-manual/R-devel/library/base/html/pipeOp.html (checked 2026-10-29). - magrittr, tidyverse project site: https://magrittr.tidyverse.org/ (checked 2026-10-29).
- Tidyverse blog, “Differences between the base R and magrittr pipes”: https://tidyverse.org/blog/2023/04/base-vs-magrittr-pipe/ (checked 2026-10-29).
- Wickham, Cetinkaya-Rundel and Grolemund, R for Data Science (2nd ed.), “Workflow: style”, Pipes section: https://r4ds.hadley.nz/workflow-style.html (checked 2026-10-29).







