Working Directories and File Paths
Use getwd(), setwd(), and here() for reliable cross-platform paths.
Working Directories and File Paths is a free R Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, and your progress syncs across the web and the CoddyKit app. The R Academy course includes 4 lessons in total.
What Is the Working Directory?
The working directory is the folder R uses as a starting point when you reference files with relative paths. It is the default location R looks in (and writes to) when you do not provide a full path. Every R session has exactly one working directory at any time.
# getwd() returns the current working directory
current_dir <- getwd()
cat('Working directory:', current_dir)
# All relative file references start from this location:
# read.csv('data.csv') <- looks in current_dir/data.csv
# source('R/helpers.R') <- looks in current_dir/R/helpers.Rsetwd() — Changing the Working Directory
setwd() changes the working directory for the current R session. It returns the previous working directory invisibly, which is useful for restoring state. Note: setwd() in scripts is discouraged in project-based workflows.
# Set a new working directory
old_dir <- setwd('/tmp')
cat('Now in:', getwd(), '\n')
# Restore original directory
setwd(old_dir)
cat('Restored to:', getwd(), '\n')
# Common anti-pattern (breaks on other machines):
# setwd('/Users/alice/Desktop/my_project') <- hardcoded!
# Better: use RStudio Projects which set wd automaticallyfile.path() — Building Portable Paths
file.path() constructs file paths by joining components with the correct separator for the operating system (/ on Mac/Linux, \ on Windows). Always use it instead of string concatenation for cross-platform compatibility.
# Build a path from components
data_path <- file.path('data', 'raw', 'sales.csv')
cat('Path:', data_path)
# On Unix: data/raw/sales.csv
# On Windows: data\raw\sales.csv
# Multiple levels
output_file <- file.path('output', '2024', 'Q1', 'report.pdf')
cat('Output:', output_file)
# Combine with getwd() for a full absolute path
full_path <- file.path(getwd(), 'data', 'sales.csv')
cat('Full path:', full_path)normalizePath() — Resolving to Absolute Path
normalizePath() converts a relative path to its canonical absolute form, resolving . (current dir) and .. (parent dir) components. This is essential when you need to store or log an unambiguous file location.
# Resolve relative paths to absolute
abs_path <- normalizePath('.')
cat('Absolute cwd:', abs_path, '\n')
# Resolve a relative path
data_abs <- normalizePath(file.path('..', 'data', 'sales.csv'),
mustWork = FALSE)
cat('Resolved:', data_abs, '\n')
# mustWork = FALSE: do not error if file does not exist yet
# mustWork = TRUE (default): error if path does not exist
# Useful for building reliable log messages or config files
cat('normalizePath demo complete')dirname() and basename()
dirname() extracts the directory portion of a path, and basename() extracts the file name portion. These are the R equivalents of Unix dirname and basename shell commands.
path <- '/Users/alice/projects/analysis/data/sales_2024.csv'
# Extract the directory
folder <- dirname(path)
cat('Directory:', folder, '\n')
# /Users/alice/projects/analysis/data
# Extract the file name
filename <- basename(path)
cat('File name:', filename, '\n')
# sales_2024.csv
# Remove file extension
name_only <- tools::file_path_sans_ext(filename)
cat('Name only:', name_only)file.exists() — Checking Before Reading
Always check whether a file exists before trying to read it to avoid cryptic error messages. file.exists() returns TRUE or FALSE and works on both files and directories.
data_file <- file.path('data', 'sales.csv')
# Check existence before reading
if (file.exists(data_file)) {
cat('File found, loading...\n')
# df <- read.csv(data_file)
} else {
cat('File not found:', data_file, '\n')
stop('Cannot proceed without data file.')
}
# Check multiple files at once
files <- c('data/a.csv', 'data/b.csv', 'data/c.csv')
exists_vec <- file.exists(files)
cat('Files found:', sum(exists_vec), 'of', length(files))Sys.getenv() — Environment Variable Paths
Environment variables store system-level paths like the home directory, temporary folder, and custom app paths. Sys.getenv() reads these values, making your code adaptable to different systems without hardcoding paths.
# Get the home directory
home_dir <- Sys.getenv('HOME')
cat('Home:', home_dir, '\n')
# Get the temp directory
tmp_dir <- Sys.getenv('TMPDIR')
cat('Temp:', tmp_dir, '\n')
# Custom environment variable (set in .Renviron)
data_root <- Sys.getenv('DATA_ROOT', unset = '/default/data')
cat('Data root:', data_root, '\n')
# Use env vars to build portable paths
config_file <- file.path(home_dir, '.config', 'myapp', 'settings.json')
cat('Config path:', config_file)path.expand() — Tilde Expansion
The tilde ~ is shorthand for the home directory on Unix-like systems, but R's file functions do not always expand it automatically. path.expand() replaces ~ with the actual home directory path.
# Expand tilde to full home path
short_path <- '~/.Rprofile'
full_path <- path.expand(short_path)
cat('Expanded:', full_path)
# e.g. /Users/alice/.Rprofile
# Useful when passing paths to external tools or logging
config_dir <- path.expand('~/.config/R')
cat('Config dir:', config_dir)
# Can expand multiple paths at once
paths <- c('~/data', '~/output', '~/scripts')
expanded <- path.expand(paths)
cat(expanded, sep = '\n')Listing Files with list.files()
list.files() (alias dir()) lists files in a directory, optionally filtered by a pattern and optionally returning full paths. It is indispensable when you need to process multiple files in a folder.
# List all files in current directory
all_files <- list.files('.')
cat('Files found:', length(all_files), '\n')
# Filter by extension
csv_files <- list.files('data', pattern = '\\.csv$', full.names = TRUE)
cat('CSV files:', length(csv_files), '\n')
# Recursive: include subdirectories
r_files <- list.files('R', pattern = '\\.R$',
full.names = TRUE, recursive = TRUE)
cat('R scripts:', length(r_files))Creating and Removing Paths
R has built-in functions to create directories and manage files. Use dir.create() to make new folders (with recursive = TRUE to create nested paths), and file.remove() to clean up temporary files.
# Create a directory (will not error if it already exists)
dir.create('output/figures', recursive = TRUE, showWarnings = FALSE)
cat('Directory created\n')
# Create a temporary file
tmp_file <- tempfile(fileext = '.csv')
write.csv(data.frame(x = 1:3), tmp_file, row.names = FALSE)
cat('Temp file:', tmp_file, '\n')
# Remove the file when done
if (file.remove(tmp_file)) {
cat('Temp file cleaned up')
}here Package — Project-Relative Paths
The here package solves the working directory problem elegantly. here::here() always builds paths relative to the project root (where the .Rproj file lives), regardless of where in the project you call it from.
# install.packages('here')
# library(here)
# Always resolves from project root:
# here('data', 'raw', 'sales.csv')
# here('R', 'helpers.R')
# here('output', 'report.html')
# Without here: setwd() headaches when script is in a subfolder
# With here: same path works from any subfolder
# Demonstrate base-R equivalent approach:
project_root <- normalizePath(file.path(getwd(), '..'), mustWork = FALSE)
data_path <- file.path(project_root, 'data', 'sales.csv')
cat('Data path:', data_path)Quick Check
You have a path string 'data/raw/../clean/sales.csv'. Which function would you use to resolve this into a clean, canonical absolute path?
File Paths — Key Takeaways
Robust file path handling is essential for reproducible R scripts:
getwd()/setwd()— get and set working directoryfile.path('a', 'b', 'c.csv')— OS-portable path constructionnormalizePath(path, mustWork = FALSE)— resolve to absolutedirname()/basename()— split path into folder and filefile.exists()— check before readingSys.getenv('HOME')— access system paths via env varspath.expand('~')— expand tilde to home dirlist.files(pattern = '\.csv$')— find files by extensiondir.create(recursive = TRUE)— safely make nested dirs- Use here package for project-relative paths in RStudio projects
# Robust file loading pattern:
data_file <- file.path('data', 'raw', 'sales.csv')
if (!file.exists(data_file)) {
stop(paste('Missing file:', normalizePath(data_file, mustWork = FALSE)))
}
# df <- read.csv(data_file)
cat('File path:', data_file, '\n')
cat('Full path:', normalizePath(data_file, mustWork = FALSE))Learn R with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 43
- Lessons
- 159
Frequently Asked Questions
Is the “Working Directories and File Paths” lesson free?
Yes — any 3 lessons of the R Academy learning path, including “Working Directories and File Paths”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The R Academy course includes 4 lessons in total.
What will I learn in “Working Directories and File Paths”?
Use getwd(), setwd(), and here() for reliable cross-platform paths. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start R Academy?
No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.
How long does the “Working Directories and File Paths” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this R Academy lesson?
Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Using source() to Load Scripts
- Comments, Style, and Readability
- Working Directories and File Paths
- R Projects and Workspace Management