RStudio Projects and here
Maria, a data analyst, has just finished a tidy little sales analysis. It works perfectly on her laptop, so she emails the R script to a teammate. He opens it, hits Run, and it dies on the very first line. The script begins with setwd("C:/Users/Maria/Documents/sales-analysis"), and there is no folder by that name on his machine. Same script, same data, instant failure.
This lesson fixes that, for good. The trouble is never the analysis. It is the two lines at the top that pin the work to one exact spot on one exact computer. Get the folder and the paths right and your code travels: it runs unchanged on a teammate's laptop, on a new machine, or on a server, with nothing to edit.
By the end of this lesson you will be able to:
- Explain why a hard-coded absolute path breaks the moment a project moves to another machine or folder
- Set up an RStudio Project so the working directory is the project root automatically, on any computer
- Use
here()to build a file path from the project root that works no matter which subfolder the code runs from
Prerequisites: you can run R and call a function, you have read a CSV into R, and you can install and load a package. The flow below is the whole journey.
An absolute path names one machine
Maria's first line points at a path like C:/Users/Maria/Documents/sales-analysis/data/sales.csv. That is an absolute path: a complete address that starts at the very top of one specific computer (here, the C: drive) and spells out every folder down to the file. It is the equivalent of a full street address with the country, city and house number. Precise, but it only exists in one place in the world.
That precision is exactly the problem. Her teammate has no C:/Users/Maria/ folder. His files live under C:/Users/Raj/, or /home/raj/ on Linux. So the address Maria wrote points at nothing on his machine, and R gives up. We can see that failure for real. The path below is hard-coded to Maria's laptop, so on this machine file.exists() honestly reports that there is no such file:
Here is what her teammate actually sees when he runs the original script. It stops before it does any work at all:
setwd("C:/Users/Maria/Documents/sales-analysis")
#> Error in setwd("C:/Users/Maria/Documents/sales-analysis") :
#> cannot change working directory
setwd() plus an absolute path is the single most common reason an R script that "works on my machine" fails on everyone else's. The fix is not a better absolute path. It is to stop writing absolute paths at all.The working directory, and paths measured from it
R is always "standing in" one folder, called the working directory. It is R's sense of you are here. Ask for it with getwd():
The alternative to an absolute path is a relative path: an address measured from the working directory instead of from the top of the drive. The relative path data/sales.csv means "starting from wherever I am standing, step into data/ and take sales.csv." No drive letter, no username, nothing tied to one machine. Build relative paths with file.path(), which joins the pieces with the correct separator for whatever operating system is running:
Let's prove a relative path actually works. We will create a small data/ folder right here, write Maria's tiny sales file into it, then read it back with nothing but a relative path:
What is it measured from?
You run read.csv("data/sales.csv") and it succeeds. Which folder did R look inside to find data/sales.csv?
data/sales.csv means "from where R is standing, go into data and take sales.csv." Change the working directory and the same text points somewhere else.An RStudio Project anchors the working directory
An RStudio Project is just an ordinary folder with one small extra file in it, named with a .Rproj extension (for example sales-analysis.Rproj). You keep everything the analysis needs inside that one folder: the data, the scripts, the output. A typical layout looks like this:
sales-analysis/ <- the project root (holds sales-analysis.Rproj)
|-- sales-analysis.Rproj <- the marker that makes this folder a Project
|-- data/
| `-- sales.csv
|-- R/
| `-- clean-data.R
`-- output/
`-- sales-plot.png
The magic is what happens when you open that .Rproj file (File > Open Project in RStudio, or double-click it): RStudio starts a fresh R session and sets the working directory to the project folder, automatically. Maria's machine, her teammate's machine, a server, it does not matter, because opening the project always makes the project root the working directory. Now this single line means the same file for everyone, with no setwd() anywhere:
# At the top of any script in the project. No setwd(), no drive letter:
sales <- read.csv("data/sales.csv") # data/ is right inside the project root
setwd(), and never write an absolute path in a script. Open the project instead, and write every path relative to the project root. The .Rproj file does the anchoring so you do not have to.One gap relative paths still cannot close
Opening a project fixes the working directory at the start. But the working directory can quietly move while your code runs, and when it does, a bare relative path breaks again. The classic case is rendering a report. When you knit an R Markdown or Quarto file that lives in a report/ subfolder, R moves the working directory into report/ for the duration of the render. So this line, which worked fine from the project root, now looks in the wrong place:
# Knitting report/analysis.Rmd moves the working directory into report/.
# So R now hunts for the file inside report/data/, which does not exist:
read.csv("data/sales.csv")
#> Error: cannot open file 'data/sales.csv': No such file or directory
The same thing happens whenever code runs from somewhere other than the root: a script sourced from a subfolder, a scheduled job, a test. The relative path is correct relative to the root, but R is no longer standing at the root. We need a way to say "from the project root" explicitly, every time, regardless of where the code happens to be running.
here() always builds from the project root
The here package solves exactly this. The function here() does not care where R is currently standing. It finds the project root on its own and builds the path from there. It works by looking in the current folder for a root marker (a .Rproj file, or a small .here file), and if it does not find one, stepping up to the parent folder, and the parent's parent, until it does. The flow:
Once it has the root, here("data", "sales.csv") joins it onto your folders and gives back a full, correct path, identical whether you call it from the root, from report/, or from a scheduled job. Let's run it. (set_here(".") drops a .here marker so here() knows this folder is the root, which in a real project the .Rproj file already does for you.)
Because here() resolves to the root no matter where the code runs, the read just works, every time:
read.csv("data/sales.csv") trusts wherever R happens to be standing. read.csv(here("data", "sales.csv")) rebuilds the path from the project root first, so it cannot be fooled by a working directory that moved. In a project, reach for here() and you never think about the working directory again.Build a path from the root
Maria saves her charts in an output/ folder inside the project, and wants the path to sales-plot.png so she can write a figure there. Using here(), build the path to output/sales-plot.png from the project root. The library(here) line is written for you; replace the blank with the call.
Show answer
library(here)
here("output", "sales-plot.png") # path to the chart, from the project root
#> [1] "/home/you/sales-analysis/output/sales-plot.png"When do you still need here()?
Your code lives in a proper RStudio Project, so opening it sets the working directory to the root. In which situation would a bare read.csv("data/sales.csv") still fail, where read.csv(here("data", "sales.csv")) would not?
References
A few authoritative, free places to take this further:
- R for Data Science (2e): Workflow, scripts and projects - the project-oriented workflow, explained by the authors of the tidyverse.
- Jenny Bryan: Project-oriented workflow - the canonical argument for why
setwd()and absolute paths should be retired. - The here package documentation - the official reference for
here()and how it finds the project root. - Using RStudio Projects (Posit Support) - how to create and open a Project, step by step.
Lesson 1 complete
You turned a fragile script into a portable one. An absolute path (C:/Users/Maria/...) names one folder on one machine, so it breaks the moment the work moves. A relative path (data/sales.csv) is measured from the working directory, so it travels, as long as everyone starts from the same folder. An RStudio Project guarantees that shared starting point: opening the .Rproj sets the working directory to the project root automatically. And here() closes the last gap, building every path from that root so it holds even when the working directory moves under you, such as when you knit a report.
Next, Lesson 2: Reproducibility with renv and git. A portable project still depends on the exact package versions it was written against, and on a record of how it changed over time. You will pin your packages with renv so the code runs the same a year from now, and track every change with git so you can always see what you did and undo it safely.