Skip to contents

boosterpak installs reusable R project packs: typed bundles of package dependencies, optional source specs, startup attachment intent, and helper-function sidecars that make a project usable without turning it into a package. It is less than a package, but more than a fistful of copied files.

boosters.toml is the project-local control file for those packs. It is not a general dependency-manifest standard and boosterpak does not depend on one. pak remains the installer, renv remains the lockfile and default project-library layer, and boosterpak sits above them as a small capability-bundle layer for reusable setup conventions. Existing projects can instead apply packs to an active user or site library without creating a project-local renv environment.

A project declares the packs it wants in boosters.toml; boosterpak::sync() resolves those packs, hydrates plain-name packages from local libraries when possible, and installs anything still missing into the selected package library. It also writes boosters/attach.R with explicit startup library() calls for packages intended to be attached. Packs can also carry exact copied helper files, so a useful project setup can be reused without separating “packages” from customized boosters/fn_*.R files.

Typical workflow

flowchart TD
  A([Start new project]) --> B(["Run init()"])
  B --> C([Declare reusable capability])
  C --> D(["Run add_pack()"])
  C --> E(["Run add_function()"])
  D --> F(["Run sync()"])
  E --> F
  F --> G[Hydrate from local libraries]
  G --> H[Install remaining with pak]
  H --> A1[Write boosters/attach.R]
  A1 --> I[Snapshot declared packages]
  F --> J[Helper files copied into boosters]
  I --> K([Edit code and helper files])
  J --> K
  K --> L(["Run save_pack()"])
  L --> M[Flat package pack or nested function pack]
  M --> N(["Run promote_pack()"])
  N --> O(["Reuse with add_pack() in another project"])
  O --> D

  classDef userAction fill:#e8f3ff,stroke:#1f6feb,color:#0b1f3a;
  classDef packageAction fill:#f6f8fa,stroke:#6e7781,color:#24292f;
  class A,B,C,D,E,F,K,L,N,O userAction;
  class G,H,A1,I,J,M packageAction;

In practice, initialize once, add pack and function capability intent over time, run sync() whenever the project should match that intent, then save and promote a pack when the setup is worth reusing. For an already initialized repo clone, skip init() and use the restore path: renv::restore(), restart R, then boosterpak::sync(mode = "restore").

A pack is deliberately typed and reviewable. Today that means packages, optional [sources], optional attach, optional copied helper functions, and optional extension from other packs. It is not an arbitrary file sprinkler; project-specific mess stays in the project, and only reusable setup invariants belong in a pack.

1. Install pak

2. Install boosterpak

pak::pkg_install("seanthimons/boosterpak")

3. Initialize the project

boosterpak::init(renv = "yes", rprofile = "yes")

This creates:

  • boosters.toml
  • boosters/packs/
  • air.toml, when enabled by settings
  • a .Rprofile startup hook, when requested

The generated boosters.toml includes boosterpak itself in [extras].declared, so the package needed to run sync() is also captured in project intent and the project lockfile. With renv = "yes", init() bootstraps only renv, pak, and boosterpak into the project library and creates the initial lockfile when auto_snapshot = true.

In non-interactive sessions, use explicit renv and rprofile arguments. The default "ask" mode never silently changes .Rprofile when user confirmation would be required.

4. Sync the project

boosterpak::sync()

Apply mode is additive. With the default renv-library strategy, it hydrates plain-name missing packages from renv-discoverable local libraries, installs anything still missing with pak, materializes missing bundled or installed helper functions, and, when auto_snapshot = true, writes boosters/attach.R and snapshots with renv. Use hydrate = FALSE to skip local reuse for stricter first-run installs.

Safely deinitialize a project

Call deinit() without component arguments in an interactive session to see a single picker containing only components that have something to clean up. All actionable components are preselected. After selection, deinit() displays the exact project paths and .Rprofile changes and asks for one final confirmation.

boosterpak::deinit()

Automation must opt out of prompts with force = TRUE. Supplying any component argument skips the picker and honors all five logical selectors:

boosterpak::deinit(
  renv = TRUE,
  boosters = TRUE,
  rprofile = TRUE,
  lockfile = TRUE,
  air = TRUE,
  force = TRUE
)

The selectors are independent, so partial cleanup is explicit. For example, the following removes only the lockfile after confirmation:

boosterpak::deinit(
  renv = FALSE,
  boosters = FALSE,
  rprofile = FALSE,
  lockfile = TRUE,
  air = FALSE
)

The cleanup is conservative. .Rprofile itself and unrelated user lines are always retained. A renv activation line is removed only when both renv and rprofile are selected and the activation is a recognized whole-line expression. Edited or ownership-unknown air.toml files, malformed managed startup markers, user/global packs, active user libraries, and session options are preserved. If the removed renv library is active, restart R before continuing. Repeating the same cleanup is an unprompted no-op.

Use an active library without a project renv

For an existing live project that should keep using its current R libraries, initialize without creating a project-local renv environment:

boosterpak::init(renv = "no", rprofile = "yes")

Then edit the generated setting in boosters.toml:

[settings]
library = "active"

boosterpak::sync() and eager pack mutations now detect and install packages in the first writable entry of .libPaths(). Source-specific install specs, helper functions, and startup attachment work normally. Active-library apply mode skips hydration and snapshotting and does not create renv/ or renv.lock. The same behavior can be selected for one call with boosterpak::sync(library = "active").

The renv package remains an installation dependency because boosterpak also supports lockfile restoration, but active-library mode does not create or load a project-local renv environment. sync(mode = "restore") remains the separate renv lockfile workflow.

Add a Pack

boosterpak::add_pack("example")

The example pack installs cli. add_pack() preserves unrelated comments and sections in boosters.toml while updating [packs].declared. For the analysis baseline of fs, here, janitor, rio, core tidyverse packages, scales, glue, digest, skimr, and bundled helper functions, add the eda pack explicitly:

boosterpak::add_pack("eda")

If the pack carries helper functions, add_pack() also copies the bundled fn_*.R files into boosters/ and refuses to overwrite existing function files unless overwrite_functions = TRUE.

Packs can mix ordinary CRAN package names with package-specific source specs. Declare every package in packages, then use [sources] only for packages that should install from another source:

name = "plotting"
description = "Plotting packages from CRAN and GitHub."
packages = ["ggplot2", "patchwork", "ggtext"]

[sources]
"ggtext" = "wilkelab/ggtext"

Here, ggplot2 and patchwork can hydrate or install by package name, while ggtext skips hydration and uses the GitHub source spec.

Package attachment is a startup layer, not installation intent. Missing attach means a pack attaches its direct packages; use attach = true for that explicit default, attach = false to install without startup attachment, or attach = ["pkg1", "pkg2"] to attach a subset. The top-level [attach] table supports enabled, declared, and exclude. Workflow packages from core and [extras], including pak, renv, and boosterpak, are installed but not attached unless explicitly listed in [attach].declared.

Add a Helper Function

boosterpak::add_function("ni")

Helper functions are materialized as boosters/fn_*.R files and tracked in [functions].installed. They are ordinary project files, so you can edit them after materialization. sync() restores missing installed helper files, but it does not overwrite local edits.

Capture and Reuse

boosterpak::save_pack("project_baseline")
boosterpak::promote_pack("project_baseline")

save_pack() captures the resolved package set and, by default, helper functions listed in [functions].installed. Use functions = "all" to capture every boosters/fn_*.R file, functions = "none" for a flat package-only pack, or a character vector for specific function names. promote_pack() and demote_pack() copy flat package-only packs as single files and nested function-bearing packs as whole directories.

boosterpak is intentionally narrow:

  • pak resolves and installs package specs.
  • renv owns project libraries, lockfiles, and exact version restoration.
  • boosterpak owns reusable project capability packs: dependencies plus the small helper files, attachment choices, and setup conventions that are too project-shaped for a package and too reusable for copy-paste.

That boundary is the point. boosterpak uses TOML for its own pack and project config, but it is not trying to be a general project requirements format.

Restore Exact Versions

boosterpak::sync(mode = "restore")

Restore mode is lockfile-exact: it restores through renv::restore() and does not hydrate.

For the full restore-mode contract and the clone-to-working walkthrough on a new machine, including the bootstrap order when boosterpak is not installed yet, see vignette("restoring-a-project", package = "boosterpak").

Troubleshooting boosterpak 0.5 init projects

If a project was initialized with boosterpak 0.5 and, after restart, boosterpak is no longer found, follow the bootstrap recipe under “Troubleshooting: boosterpak absent from the lockfile” in vignette("restoring-a-project", package = "boosterpak").

Inspect

boosterpak::status()
boosterpak::list_packs()

status() reports whether the project config exists and validates, what packs and packages resolve, whether project-local renv appears active, whether renv.lock exists, whether boosters/attach.R exists, and whether .Rprofile contains the startup hook.