Remove bad patterns in your R code in the blink of an eye.
I’m very excited to introduce Jarl1, a new R linter. A linter is a tool that statically parses code (meaning that it doesn’t run the code in question) and searches for patterns that are inefficient, hard to read, or likely bugs.
Jarl can parse dozens of files and thousands of lines of code in milliseconds. Here is an example of Jarl running on r-source (approximately 1000 files and 200k lines of R code) in about 700 milliseconds:
On top of that, Jarl can apply automatic fixes2.
Suppose that we have the following file foo.R:
x <- any(is.na(mtcars))
f <- function(x) {
apply(x, 1, mean)
}There are two rule violations in this file:
any(is.na(mtcars)) should be replaced by anyNA(mtcars)3;apply(x, 1, mean) should be replaced by rowMeans(x)4.Instead of fixing those cases by hand, we can run the following command in the terminal (not in the R console):
jarl check foo.R --fixAfter running this, foo.R now contains the following code:
x <- anyNA(mtcars)
f <- function(x) {
rowMeans(x)
}(Note that f is now useless since it is equivalent to rowMeans().)
Jarl stands on the shoulders of giants, in particular:
lintr rules.Jarl is a single binary, meaning that it doesn’t need an R installation to work. This makes it a very attractive option for continuous integration for instance, since it takes less than 10 seconds to download the binary and run it on the repository.
There are two ways to use Jarl:
jarl check [OPTIONS];The Jarl extension enables code highlighting and quick fixes. The former means that code that violates any of the rules in your setup (more on this below) will be underlined and will show the exact violation when hovered.
The latter adds a lightbulb button next to rule violations, allowing you to selectively apply fixes or ignore violations.
In the future, those extensions could have a “Fix on save” feature similar to the “Format on save” functionality provided by Air.
By default, Jarl will report violations for almost of its rules.
It is possible to configure its behavior using a configuration file named jarl.toml.
In particular, in this file, you can specify:
and more.
Jarl is in its early days, there are more rules and options to add.
Still, it can already be used in interactive use or in continuous integration (check out the setup-jarl workflow!).
Eventually, many lintr rules should be supported in Jarl, but the end goal is not to have perfect compatibility.
lintr provides many rules related to code formatting (e.g. spaces_inside_linter).
Those will not be integrated in Jarl since they are already covered by Air.
Additionally (for now), Jarl cannot perform semantic analysis5, meaning that some lintr rules are out of scope (e.g. unreachable_code_linter).
This was a very light introduction, go to the Jarl website for more information.
If you want to help developing Jarl, check out the “Contributing” page. Jarl is written in Rust, which may be a barrier to contributing but is also a very powerful language which is a real pleasure to use. I will add a more detailed tutorial soon so that this can also be a nice introduction to this language. You can also contribute to the documentation!
As I said above, Jarl depends enormously on the work of lintr and Air developers, so thank you!
Jarl is also very inspired by similar tools in other languages, in particular Ruff in Python and Cargo clippy in Rust.
Finally, thanks to the R Consortium for funding part of the development of Jarl via the ISC Grant Program.
And thank you, Maëlle, for improving the draft!
Jarl stands for “Just Another R Linter”.↩︎
This is not always possible, it depends on the rule.↩︎
anyNA(x) is more efficient than any(is.na(x)).↩︎
rowMeans(x) is more efficient than apply(x, 1, mean).↩︎
Semantic analysis refers to using the context surrounding an expression to explore rule violations.↩︎
If you see mistakes or want to suggest changes, please create an issue on the source repository.
Text and figures are licensed under Creative Commons Attribution CC BY 4.0. Source code is available at https://github.com/etiennebacher/personal_website_distill, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".
For attribution, please cite this work as
Bacher (2025, Nov. 20). Etienne Bacher: Jarl: just another R linter. Retrieved from https://www.etiennebacher.com/posts/2025-11-20-introducing-jarl/
BibTeX citation
@misc{bacher2025jarl:,
author = {Bacher, Etienne},
title = {Etienne Bacher: Jarl: just another R linter},
url = {https://www.etiennebacher.com/posts/2025-11-20-introducing-jarl/},
year = {2025}
}