recipes, a pipeline of preprocessing steps for tidymodels
Pipeable steps for feature engineering and data preprocessing to prepare for modeling
At a glance
- What is it?
- The tidymodels recipes package lets you build a feature engineering plan as a sequence of pipeable steps, so the transformations applied to training data are defined once and applied identically at prediction time. The catch is that the API is R-specific and the plan is tied to the model matrix workflow, not to arbitrary data frames.
- Who is it for?
- recipes suits an R team that has adopted tidymodels and wants a preprocessing plan that is defined once, applied identically at fit and predict time, and readable as a sequence of named steps. It does not suit a team working outside the tidymodels workflow, since the plan is built around a formula and a model matrix, and it does not suit a project that needs the raw, untransformed columns for anything other than modeling.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 36 days ago.
- What is it written in?
- Mainly R, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A preprocessing plan defined once, applied twice
The tidymodels recipes package exists to make feature engineering declarative. The project describes it as pipeable steps for feature engineering and data preprocessing to prepare for modeling, and the documentation opens with a promise: use dplyr-like pipeable sequences of feature engineering steps to get your data ready for modeling.
The example is short enough to take in at a glance.
library(recipes)
data(ad_data, package = "modeldata")
ad_rec <- recipe(Class ~ tau + VEGF, data = ad_data) |>
step_normalize(all_numeric_predictors())
ad_recA formula, a data set and one step. The result is a recipe object, and printing it shows the plan.
The problem it addresses is the classic one in modeling pipelines. You have a preprocessing step, a model fit, and a prediction step, and the preprocessing has to be applied identically in both places or the predictions are wrong. The R ecosystem already had long-standing ways to build design matrices, also known as model matrices, through formulas and `model.matrix`, and the documentation is explicit that those have limitations to what the existing infrastructure can do.
So the alternative being offered is a plan, built up from steps, that records what you want done. The plan is then baked, which is what makes the fit-time and predict-time application identical rather than two code paths you have to keep in sync by hand.
The audience is an R user who has adopted tidymodels and wants the preprocessing to live in the same object as the model specification, in the same pipeable style as the rest of the tidyverse. The homepage is recipes.tidymodels.org, and the package sits on CRAN with a stable lifecycle badge.
The formula is the anchor, not the data frame
The most important structural decision in the package is that a recipe is built from a formula and a data set rather than from a data frame plus a set of column names.
In the example, `recipe(Class ~ tau + VEGF, data = ad_data)` names the outcome, Class, and two numeric predictors. The right-hand side of the formula tells the package which columns are predictors, and the left-hand side tells it which is the outcome. That single piece of information is what lets the step functions work, because `all_numeric_predictors()` does not need to be told which columns are numeric, and a step that targets the outcome does not need to be told what the outcome is called.
That is why the selector vocabulary in tidymodels is what it is. A step asks for columns by role, and the role comes from the formula. It also means a recipe is not a general data transformation tool, and this is the boundary an adopter should understand before reaching for it.
A pipeline that reshapes a data frame, joins tables, imputes a value based on a lookup from another table, or aggregates rows is not what a recipe is for. A recipe describes a design matrix for a model, with an outcome, predictors, and transformations that make those predictors usable by an estimator.
The same reasoning explains why the alternative is a real alternative rather than a marginal preference. R formulas and `model.matrix` produce a design matrix directly, and they are much less code. The limitation the documentation points at is that formulas are not designed for reuse in a pipeline that has to apply the same transformation to new data at predict time, and a model matrix built by hand does not carry the record of what was done to it. The recipe carries that record, and that is the trade.
The step vocabulary is broad in the sense that tidymodels ships many steps for imputation, encoding, filtering, transformation and more, but the shape of each one is consistent: a step takes selectors and options, and returns a new step. Because they are R functions operating on data frames, they compose with the native pipe.
Installing recipes, and the pak route for the development version
Installation is the standard R story with three documented options, and the first one is the one most users should take.
# The easiest way to get recipes is to install all of tidymodels:
install.packages("tidymodels")
# Alternatively, install just recipes:
install.packages("recipes")
# Or the development version from GitHub:
# install.packages("pak")
pak::pak("tidymodels/recipes")Installing the whole of tidymodels is called the easiest way to get recipes, which tells you something about how the packages relate to each other. `recipes` is one member of a family, and its companions are the ones that consume a recipe: the modelling packages that take a baked recipe and produce a fitted model. Installing the family together avoids the version-alignment problem between them, and it is the path the documentation recommends.
Installing just `recipes` is for the case where you want the preprocessing layer and your modelling comes from somewhere else.
The third route is for development, and it introduces `pak`, the package manager from the same organisation. The comment notes that pak itself has to be installed first, and then `pak::pak("tidymodels/recipes")` fetches the GitHub version. The point of pak is that it resolves the recursive dependencies of a GitHub package, which `install.packages` will not do for a source that is not on CRAN, so the command is more than a convenience wrapper.
For a first real use, the example in the introduction is the whole tutorial. Load the package, load a data set with `data(ad_data, package = "modeldata")`, build a recipe from a formula, pipe a step into it, and print the object to see the plan. The data set comes from the `modeldata` package, which is part of the tidymodels organisation's companion packages for example data.
The printed recipe is worth reading carefully, because it is the artifact you will be reading in a review. It lists the outcome, the predictors, the roles assigned to each column, and every step with its options. A plan that is legible when printed is a plan a colleague can check.
A 1.x line where the step set is still growing
The release history shows a package on a stable 1.x line with a steady cadence. The recorded versions are 1.4.0 from 2026-08-24, 1.3.3 from 2026-05-30 and 1.3.2 from 2026-04-02, and the last push to the repository was on 2026-09-17. The lifecycle badge on the README reads stable.
For a package that ships on CRAN, that is a healthy pattern, and the tidymodels packages generally are careful about backwards compatibility because they are depended on by each other and by a large body of user code.
The practical consequence for an adopter is that the step vocabulary is the API, and it grows over time. A step you read about in a blog post may not exist in the version you have, and a step that exists may gain options. Since the plan is printed and often stored, the sensible practice is to record the package version alongside any saved plan rather than assuming a plan is portable.
The repository layout shows the structure of a serious R package rather than a script collection. There is a `DESCRIPTION` file, a `NAMESPACE`, `R/` for the source, `man/` for the generated documentation, `man-roxygen/` for the templates that generate it, `tests/`, `vignettes/`, `inst/`, a `recipes.Rproj` project file, a `_pkgdown.yml` and a `pkgdown/` directory for the documentation site, a `revdep/` directory for reverse dependency checks, `NEWS.md` for the changelog, and a `contributors.md`.
Two of those deserve a mention for what they signal. `revdep/` means the package checks the packages that depend on it, which is how a change to a public API gets noticed before it breaks someone. And `air.toml` next to the `.editorconfig` and the `.pre-commit-config.yaml` in the tree suggests a move to the Air formatter for R, which is a formatting preference rather than anything functional.
One thing to check before shipping: the licence recorded for this repository is a custom type that GitHub cannot classify, and the repository carries both a `LICENSE` and a `LICENSE.md` file at the top level. The tidymodels packages are generally permissive, but the file is the authoritative answer for this repository, and it is the file to read rather than the badge.
Where recipes does not reach
The boundaries of the package follow from its purpose, and they are worth stating precisely because the word preprocessing covers a lot of ground.
The first boundary is that a recipe is tied to a formula and a model matrix. It is a description of how to turn columns into a design matrix for an estimator. If what you need is a general, reusable data cleaning function, a recipe is the wrong shape, and there are better tools for that in R.
The second boundary is the data type. The steps operate on data frames and produce model matrices. A dataset that is a database table, a Parquet file on disk, or a Spark data frame is not what the steps expect, and getting it into shape before the recipe is your problem. The package does not solve data engineering, it solves the boundary between data engineering and modeling.
The third is the language. This is an R package, and the whole design is built on R's formula interface, its data frame semantics and the tidyverse's pipe and selector conventions. There is no Python equivalent here, and a team whose modeling stack is scikit-learn or a transformer pipeline should look at those instead, where the same idea of a declared, reusable transformation pipeline is expressed with a different set of primitives.
The fourth boundary is about what the plan actually guarantees. A recipe records the transformations and bakes them so the same ones run at predict time. It does not validate your data, detect leakage, or tell you whether a feature is a good idea. If you fit a recipe on data that includes information unavailable at prediction time, the plan will faithfully reproduce that mistake.
What recipes does buy is reproducibility that is legible. Instead of a script that mutates a data frame in three places, you have a named object listing the steps, printed in order, with their options, that you can put in a report and that a reviewer can argue about.
Editorial conclusion
recipes suits an R team that has adopted tidymodels and wants a preprocessing plan that is defined once, applied identically at fit and predict time, and readable as a sequence of named steps. It does not suit a team working outside the tidymodels workflow, since the plan is built around a formula and a model matrix, and it does not suit a project that needs the raw, untransformed columns for anything other than modeling. Verify first that the steps you need exist in the package you are on, since the feature set grew across the 1.x line and the step names are part of the public API, and check the licence file in the repository before shipping it in a commercial product, because the licence type recorded for this repository is one GitHub cannot classify.
Frequently asked questions
What is the tidymodels recipes package for?
It lets you build a feature engineering plan as a sequence of pipeable R steps, using dplyr-like syntax, so the preprocessing applied before modeling is defined once. The plan is then applied consistently at fit time and at prediction time, which is the problem it is designed to solve.
How do I install recipes in R?
The documentation calls install.packages("tidymodels") the easiest way to get recipes, and install.packages("recipes") installs just this package. For the development version from GitHub you install pak first and then run pak::pak("tidymodels/recipes").
How do I create a recipe with a normalization step?
Call recipe() with a formula and a data set, then pipe a step into it with the native pipe, for example recipe(Class ~ tau + VEGF, data = ad_data) |> step_normalize(all_numeric_predictors()). Printing the result shows the plan with the outcome, the predictors and each step.
Can recipes be used for general data cleaning outside modeling?
The package is described as an alternative method for creating and preprocessing design matrices for modeling or visualization, so it is aimed at the modeling boundary rather than general data engineering. Steps operate on data frames and a formula that names the outcome and the predictors, and the selectors such as all_numeric_predictors() derive their targets from that formula.
What licence does the recipes package use?
The repository is recorded with a custom licence type that GitHub cannot classify, and it ships both a LICENSE and a LICENSE.md file at the top level. Read those files for the authoritative terms rather than relying on the repository metadata field.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tidymodels-recipes)Was this useful?