
Developing packages with rix
Source:vignettes/g-developing-packages-with-rix-environments.Rmd
g-developing-packages-with-rix-environments.RmdWhy bring {rix} into your package workflow?
This vignette walks through a recommended development loop for package authors:
- Declare the package dependencies with rix.
- Commit the resulting
default.nixto the repository. - Use the same definition locally and in CI/CD (for example GitHub Actions).
- Refresh the snapshot frequently so that you notice upstream changes early.
Declaring your package environment
Start by calling rix() from your package root. List the
R packages and system tools that your package requires for development,
testing, or vignette builds:
rix(
r_ver = "bleeding-edge",
r_pkgs = c(
"devtools", "rcmdcheck", "roxygen2", # package development helpers
"jsonlite", "httr" # package runtime deps
),
system_pkgs = c("pandoc"), # or anything else
ide = "none",
path = "default.nix",
overwrite = TRUE
)A few tips when shaping the environment:
- Prefer
r_ver = "bleeding-edge"(or at least a very recent date). This aligns your local setup with what users will experience soon and surfaces compatibility problems early. Seevignette("z-bleeding_edge.Rmd")for more details on using"bleeding-edge". - If you use a fixed date, then keep
datecurrent. Updating it every few weeks lets you track CRAN, nixpkgs, and system toolchain updates. If the new snapshot fails you can fix issues right away instead of facing a large backlog later, or you could always revert to an earlier working date.
Committing the environment to your repository
Place the default.nix file at the root of the package
repository so that contributors can run:
This drops them into a shell with the right environment for contributing.
To simplify onboarding, document in README.md (or a
contributing guide) that contributors should run nix-shell
before working on the package.
Because the environment is pinned, collaborators and CI jobs execute the same versions of your dependencies, eliminating “works on my machine” bugs.
Keeping the snapshot fresh
You could setp up a CI action to update the environment frequently, which would then trigger unit tests on CI as well. If the tests fail you can immediately address incompatibilities introduced by recent CRAN changes.
Using {rix} in GitHub Actions
Because default.nix captures the entire toolchain, you
should use it as the basis for your CI workflow. Below is a minimal
GitHub Actions configuration thatruns your package’s unit tests:
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
name: devtools-tests-via-r-nix
permissions:
contents: read
jobs:
devtools_test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest]
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Create this folder to silence warning
run: mkdir -p ~/.nix-defexpr/channels
- name: Create .Renviron
run: |
echo "GITHUB_PAT=${{ secrets.GITHUB_TOKEN }}" >> ~/.Renviron
shell: bash
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=https://github.com/rstats-on-nix/nixpkgs/archive/refs/heads/r-daily.tar.gz
- uses: cachix/cachix-action@v14
with:
name: rstats-on-nix
- name: devtools::test() via nix-shell
run: nix-shell --run "Rscript -e \"devtools::test(stop_on_failure = TRUE)\""The workflow builds the same shell you use locally and uses our
rstats-on-nix binary cache for fast, reproducible builds.
Any failure signals that newly published CRAN may be incompatible.
Having the tests run on a schedule is a safe way to catch them very
early and avoid the dreaded 2 weeks notice from CRAN to fix your
package!
Summary
By defining your package environment with rix,
committing the default.nix, and reusing it across local
development and CI/CD, you build confidence that your package remains
compatible with the evolving R ecosystem. Regularly updating the
snapshot keeps you close to the latest CRAN state while still benefiting
from the reproducibility that Nix provides.