How to get R Console working in Positron with Nix and direnv setup?

Here’s a concise and clear version of your question for posting to Posit Community or Positron support:


:question: How can I get the R Console to start in Positron with a Nix + direnv setup?

I’m using Nix with direnv to configure my development environment, and I launch R through a shell.nix file like this:

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = [
    pkgs.R
    pkgs.python3
    pkgs.bashInteractive
    pkgs.glibcLocales
  ];

  shellHook = ''
    export LANG=en_US.UTF-8
    export LC_ALL=en_US.UTF-8
    export R_HOME=$(${pkgs.R}/bin/R RHOME)
    export PATH=${pkgs.R}/bin:$PATH
  '';
}

My .envrc simply contains:

use nix

Everything works as expected in a normal terminal:

  • R runs
  • $R_HOME is set
  • IN_NIX_SHELL=impure

But in Positron:

  • The R Console fails to start
  • The terminal inside Positron reports R: command not found
  • I confirmed that direnv is not sourcing .envrc in that terminal

I also tried adding this to settings.json:

"positron.r.customBinaries": [
  "/nix/store/.../bin/R"
]

But it still doesn’t start the R console.


:white_check_mark: What I’m looking for:

  • How can I ensure Positron terminal and R console run inside my Nix shell ?
  • Is there a Positron-specific way to load .bashrc or .envrc?
  • Should I create a wrapper script or use a login shell setting?

Let me know if anything else should be included. I’m happy to share logs or exact paths if needed.


Let me know if you want to customize that more, or I can post it in a format suitable for GitHub issues, community.posit.co, or Stack Overflow.

1 Like

I’m curious if you found a solution. I’ve been hammering away at this for a few days to no avail


title: "Positron + Nix R (Remote-SSH) — A Verified Architecture"
subtitle: "Reliable, reproducible interpreter selection for remote Nix environments in the Positron IDE"
author: "Your Name / Your Team"
format:
html:
toc: true
toc-depth: 3
theme: cosmo
code-copy: true
embed-resources: true
smooth-scroll: true
code-fold: true

Overview

This guide provides a verified, production-safe method for making the Positron IDE reliably use an R environment provided by Nix during a Remote-SSH session. It is specifically for the Positron IDE, not standard VS Code.

This architecture solves common and subtle failure points discovered through extensive troubleshooting:

  • IDE Rejection: Positron's R Language Pack rejecting Nix's R wrapper due to missing validation markers.
  • Environment Mismatch: Positron starting the correct R binary but failing to load the Nix environment, resulting in missing packages and environment variables.
  • Configuration Errors: Failures from using ${workspaceFolder} in settings and syntax conflicts within the flake.nix shellHook.

The Solution

The final, verified strategy is to use a project-local .Renviron file. This file is automatically generated by the flake.nix shellHook every time you enter the environment. When Positron starts an R session in your project directory, R automatically reads this file, correctly setting up its own library paths and environment variables.

Outcomes

  • A flake-based dev shell with R, Python, and all necessary dependencies.
  • A .Renviron file that makes the Nix environment available to Positron R sessions.
  • A stable, project-local symlink to the R binary for easy configuration.
  • A comprehensive troubleshooting guide for Positron-specific issues.

1. Directory Layout

Replace placeholders like /path/to/projects and <your-username> with your own values.

/path/to/projects/
├─ my-local-package/         # Optional: A local R package (as a git repo)
└─ my-project/               # The main project directory
   ├─ flake.nix             # The heart of the Nix environment
   ├─ .envrc                # For automatic activation with direnv
   └─ .vscode/
      └─ settings.json       # Positron settings (scoped to the remote host)

2. flake.nix

This is the most critical file. It defines all dependencies and contains the shellHook that generates the .Renviron file.

{
  description = "A reproducible R and Python environment for Positron";

  inputs = {
    # Pinning to a stable channel is recommended for production.
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
    # Example for a local package dependency.
    # my-local-package.url = "git+file:///path/to/projects/my-local-package";
  };

  outputs = { self, nixpkgs, ... }@inputs:
    let
      system = builtins.currentSystem or "x86_64-linux";
      pkgs = import nixpkgs {
        inherit system;
        config.allowUnfree = true;
      };

      # Define your R environment with all packages.
      # IRkernel is included for optional Jupyter notebook support.
      wrappedR = pkgs.rWrapper.override {
        packages = with pkgs.rPackages; [
          tidyverse
          arrow
          odbc
          DBI
          IRkernel
          # Add other required R packages here...
          # And your local package if you have one:
          # myLocalPackage
        ];
      };

    in {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = with pkgs; [
          wrappedR
          (python3.withPackages (ps: [ ps.pandas ps.ipykernel ps.jupyterlab ]))
          unixODBC 
          unixODBCDrivers.msodbcsql18 # Example ODBC driver
          glibcLocales
        ];

        shellHook = ''
          # --- Basic Environment Setup ---
          export LANG="en_US.UTF-8"
          unset LD_PRELOAD # Prevents SIGABRT crashes in IDE sessions

          # --- Create a stable, project-local symlink to R ---
          # Positron will point to this file.
          mkdir -p .nix-bin
          ln -sf "$(which R)" .nix-bin/R

          # --- The Core Solution: Generate a project-local .Renviron file ---
          # This injects the Nix environment into the R session started by Positron.
          # The '--vanilla' flag is CRITICAL to prevent R from reading a stale/corrupted
          # .Renviron file while trying to generate a new one, which causes a loop.
          R_LIBS_SITE_VALUE=$(${wrappedR}/bin/R --vanilla -q --slave -e 'cat(Sys.getenv("R_LIBS_SITE"))')
          
          # The ''${...} syntax is a Nix-specific escape to ensure the shell,
          # not Nix, expands the R_LIBS_SITE_VALUE variable.
          cat > .Renviron <<EOF
R_LIBS_SITE=''${R_LIBS_SITE_VALUE}
ODBCSYSINI=$(pwd)/.odbc
LANG=en_US.UTF-8
EOF
          # Explicitly ensure LD_PRELOAD remains unset within the R session.
          echo "LD_PRELOAD=" >> .Renviron

          echo "✅ Project environment ready (with .Renviron for Positron)"
        '';
      };
    };
}

3. .envrc

Create this file in your project root to enable automatic environment activation with direnv.

use flake --impure

After creating it, run direnv allow in your terminal.


4. settings.json

This file configures Positron for your project. Crucially, it uses a hardcoded absolute path, as Positron's R Language Pack does not reliably expand the ${workspaceFolder} variable.

Create this file at .vscode/settings.json inside your project directory. Remember to replace the placeholder path.

{
  "positron.r.interpreters.default": "/path/to/projects/my-project/.nix-bin/R",
  "positron.r.interpreters.startupBehavior": "manual",
  "positron.r.kernel.logLevel": "debug"
}

5. Final Setup and Test

  1. Initialize the Environment: Navigate to your project directory and run nix develop once. This will execute the shellHook, create the .Renviron file, and set up the .nix-bin/R symlink.
  2. Clean Restart (Mandatory):
    • On the remote server, kill any lingering Positron processes: pkill -f .positron-server || true
    • On your local machine, completely quit the Positron IDE (File > Exit).
  3. Test in Positron:
    • Restart Positron and connect to your remote server.
    • Open your project folder.
    • Open an R file or start the R console. It should now use your Nix-provided R.
    • Verify by running .libPaths() (it should show many /nix/store paths) and library(tidyverse) (it should load successfully).

6. Troubleshooting

Symptom Diagnosis Solution
R session starts, but library() fails with "package not found". The .Renviron file is missing, corrupted, or not being read. Verify the shellHook in your flake.nix is correct. Delete the old .Renviron (rm .Renviron) and re-run nix develop.
Positron log shows ... is not absolute...ignoring. You are using ${workspaceFolder} in your settings.json. Positron's R Language Pack does not expand this variable. Replace ${workspaceFolder} with the hardcoded, absolute path to your project's .nix-bin/R file.
nix develop fails with an "undefined variable" error. The shellHook has a syntax error. Nix is interpreting a shell variable ${...} as a Nix variable. Use the Nix-specific escape syntax: ''${...}. For example, R_LIBS_SITE=''${R_LIBS_SITE_VALUE}.
The .Renviron file is full of the R startup banner text. The R command in the shellHook is running in interactive mode and its output is polluting the file. Add the --vanilla -q --slave flags to the R command in your shellHook to make it run silently.
Positron shows no R interpreters at all. Your settings.json path is incorrect, or the .nix-bin/R file does not exist or is not executable. Double-check the absolute path in settings.json. Run ls -l .nix-bin/R to ensure the symlink exists. Run nix develop to regenerate it.

I removed this. But I guide that I have verified is in my other comment.