Library / SDK
tidyverse/glue avatar
tidyverse/glue

glue puts R expressions inside curly braces and evaluates them

Glue strings to data in R. Small, fast, dependency free interpreted string literals.

750 stars67 forksRNOASSERTION

At a glance

What is it?
glue is a small, fast, dependency-free R package that does string interpolation by embedding R expressions in curly braces, and the two functions you actually use are glue() and glue_data(). Its distinguishing property is predictability: what you see in the source is nearly what you get in the output, including the whitespace handling, which is where paste() and sprintf() get in the way.
Who is it for?
Adopt glue if you build strings out of data in R and are tired of paste() and sprintf() noise, since the output is close to the literal you wrote and the package has no dependencies.
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?
Activity is slowing. The repository last received commits 6 months 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

The mechanism is an R expression in curly braces

glue offers interpreted string literals that are small, fast, and dependency-free. It does this by embedding R expressions in curly braces, which are then evaluated and inserted into the string.

That is the whole idea, and the example is short enough to take in at a glance:

r
library(glue)

name <- "Fred"
glue("My name is {name}.")
#> My name is Fred.

The braces are not a templating placeholder that you fill in. They contain R code, and that code is evaluated. So you are not limited to using a bare symbol inside `{}`, it can be any little bit of R code:

r
name <- "Pebbles"
glue("Here is my name in uppercase and doubled: {strrep(toupper(name), 2)}.")
#> Here is my name in uppercase and doubled: PEBBLESPEBBLES.

The dependency-free claim matters more here than it would for a larger package. glue does not need a parser, a template engine or an evaluation environment beyond the one R already has, because R's own parser can evaluate the expression between the braces. The result is that the package is small and the behaviour matches what R already does everywhere else, rather than being a second language with subtly different rules.

There is also a stringr alias. `stringr::str_glue()` is an alias for `glue::glue()`, so if you have already attached stringr, or the whole tidyverse, you can use `str_glue()` to access all of the functionality of `glue()`.

The package is MIT licensed according to the project listing, the last push was on 2026-04-21, and the releases are v1.8.1 from 2026-04-17, v1.8.0 from 2024-09-30 and v1.7.0 from 2024-01-10. The homepage is glue.tidyverse.org.

Data can come from the environment, from arguments, or from a frame

glue can interpolate values from the local environment or from data passed in `name = value` form:

r
x <- "the local environment"
glue(
  "`glue()` can access values from {x} or from {y}. {z}",
  y = "named arguments",
  z = "Woo!"
)
#> `glue()` can access values from the local environment or from named arguments. Woo!

So there are two sources in one call, and a name given as an argument wins over the same name in the environment. That is what makes the function usable in both a script and a function without a separate parameter-passing convention.

If the relevant data lives in a data frame, or a list or an environment, use `glue_data()` instead:

r
mini_mtcars <- head(cbind(model = rownames(mtcars), mtcars))
glue_data(mini_mtcars, "{model} has {hp} hp.")
#> Mazda RX4 has 110 hp.
#> Mazda RX4 Wag has 110 hp.
#> Datsun 710 has 93 hp.
#> Hornet 4 Drive has 110 hp.
#> Hornet Sportabout has 175 hp.
#> Valiant has 105 hp.

And glue_data() is very natural to use with the pipe:

r
mini_mtcars |>
  glue_data("{model} gets {mpg} miles per gallon.")
#> Mazda RX4 gets 21 miles per gallon.
#> Mazda RX4 Wag gets 21 miles per gallon.
#> Datsun 710 gets 22.8 miles per gallon.
#> Hornet 4 Drive gets 21.4 miles per gallon.
#> Hornet Sportabout gets 18.7 miles per gallon.
#> Valiant gets 18.1 miles per gallon.

Those examples also demonstrate that `glue()` is vectorized over the data. The output is one string per row, which is the behaviour that makes glue_data() a reporting function rather than a formatting helper.

That vectorisation is also the performance consideration. Each expression in the braces is evaluated once per element, so putting something expensive inside the braces multiplies its cost by the length of the data. The usual advice of computing the value once outside and interpolating the name is worth following, and the package's smallness makes it easy to have a hundred calls to glue_data() in a script without noticing.

The whitespace rules are the part that changes your code

The section titled what you see is awfully close to what you get is about prediction, and the specific claim is that there is considerably less syntactical noise and mystery compared to `paste()` and `sprintf()`.

The concrete mechanism is trimming. Empty first and last lines are automatically trimmed, as is leading whitespace that is common across all lines. You do not have to choose between indenting your code properly and getting the output you actually want.

The example shows what that means inside a function body:

r
foo <- function() {
  glue("
    A formatted string
    Can have multiple lines
      with additional indentation preserved")
}
foo()
#> A formatted string
#> Can have multiple lines
#>   with additional indentation preserved

The leading whitespace that is common to all 3 lines is absent from the result, while the extra indentation on the third line is preserved. That is the rule: indentation that is common to every line is stripped, indentation that is relative to the common level is kept.

This is the feature that makes glue different from sprintf, where a multi-line format string has to be written with explicit newline and padding, and from paste, where you end up calling trimws() and gsub() to clean up afterwards. Here the cleanup is part of the function, which means a formatted message inside an indented function body looks the way you wrote it.

The trade-off is that glue's output is not a literal you can paste back into R and get the same string, since the trimming is destructive. For a log message or a report line that is exactly what you want. For something you intend to round-trip through a parser it is not.

Beyond the two functions there are SQL helpers and knitr engines

glue is a relatively small and focused package, but there is more to it than the basic usage of `glue()` and `glue_data()` shown above, and the documentation lists the rest.

The vignettes are the main path into it. The Get started article demonstrates more interesting features of `glue()` and `glue_data()`. How to write a function that wraps glue shows how to write your own glue wrapper functions that work as expected inside other functions, which is a problem that the trimming rules make non-obvious, since a wrapper that adds indentation would have that indentation stripped.

Then there are the specialised functions. `glue_sql()` and `glue_data_sql()` are for producing SQL statements, which is a case where you want interpolation but with the quoting rules of a database, and glue provides dedicated functions rather than leaving you to compose it yourself.

And glue provides a couple of custom knitr engines that allow you to use glue syntax in chunks, so a document can be written with interpolation in it rather than with chunk output pasted back in.

The repository structure reflects how a tidyverse package is built. There is a DESCRIPTION file, a NAMESPACE, the R/ directory for the code, src/ for compiled parts, tests/, vignettes/, man/ for the generated help pages, and a pkgdown/ directory for the website. There is also a .aspell/ directory, which is a tidyverse convention for maintaining a spelling dictionary for the documentation, and a revdep/ directory for reverse dependency checks, which is how a package finds out whether a change to it breaks something downstream.

The README is generated from README.qmd, which is the Quarto source, and the repository carries a cran-comments.md file and a MAINTENANCE.md, both of which point at the fact that this is a package with real submission obligations rather than a script.

The versioning and the release channel tell you how fast it moves

glue sits in the tidyverse, and its release history shows a project that is maintained on a slow, careful cadence rather than a fast one.

The three recent versions are v1.8.1 published on 2026-04-17, v1.8.0 on 2024-09-30 and v1.7.0 on 2024-01-10. So a minor version is a long event and a patch release comes when a fix is warranted, with the last push to the repository on 2026-04-21 sitting four days after the v1.8.1 tag.

That is a deliberate shape for a package that many other packages depend on. glue is small and its API is stable, so a release is not an event in the way a new major version of a framework is. The risk of upgrading is low and the churn is minimal.

The two install channels reflect the same idea. The CRAN version is the released one and is what `install.packages("glue")` gives you. The GitHub version, obtained with `pak::pak("tidyverse/glue")`, is the development build, and the documentation keeps them in separate sections so it is clear which is which.

The licence is listed as Other, a custom licence GitHub cannot classify, with the terms in the LICENSE file and a separate LICENSE.md. A package with this much downstream dependency is not going to change its licence, so that is a one-time check rather than a recurring one.

The package also ships a code of conduct, released with a Contributor Code of Conduct, and by participating in the project you agree to abide by its terms. For a package in the tidyverse that is a formality, but it is there.

Editorial conclusion

Adopt glue if you build strings out of data in R and are tired of paste() and sprintf() noise, since the output is close to the literal you wrote and the package has no dependencies. Skip it if your strings need to be localised, since glue evaluates R expressions and is not a translation catalogue, and if you are working in a language other than R. Verify first which version your environment resolves, because the CRAN release and the GitHub development version differ, and that your expressions inside the braces are cheap, since glue evaluates them once per element when the input is vectorised.

Frequently asked questions

How do I install glue?

The released version comes from CRAN with `install.packages("glue")`, and the development version from GitHub with `pak::pak("tidyverse/glue")`. The package is dependency-free, so there is nothing else to install.

What is the difference between glue() and glue_data()?

glue() interpolates from the local environment or from data passed in name = value form, while glue_data() takes a data frame, list or environment and interpolates one string per element, which makes it vectorized over the data.

How does glue handle indentation in multi-line strings?

Empty first and last lines are automatically trimmed, as is the leading whitespace common to all lines, while relative extra indentation is preserved. So a formatted string written inside an indented function body comes out at the margin, with the relative shape of the original intact.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. tidyverse/glue on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tidyverse-glue.svg)](https://hysenlabs.com/projects/tidyverse-glue)

Was this useful?