What is the difference between $PATH and $fpath?
Categories:
Understanding $PATH vs. $fpath: Navigating Your Shell's Executables and Functions

Explore the critical differences between $PATH and $fpath in Unix-like systems, particularly macOS, and learn how they govern command execution and shell function discovery.
In Unix-like operating systems, especially macOS, the shell relies on several environment variables to locate files and commands. Among the most fundamental are $PATH and $fpath. While both deal with finding things, they serve distinct purposes: $PATH is for executable programs, and $fpath is for shell functions. Understanding their roles is crucial for efficient shell scripting, command-line usage, and troubleshooting 'command not found' errors.
What is $PATH?
The $PATH environment variable is a colon-separated list of directories that your shell searches when you type a command. When you execute a command like ls, grep, or a custom script, the shell iterates through the directories listed in $PATH from left to right, looking for an executable file with that name. The first one it finds is the one it executes. This mechanism allows you to run commands without specifying their full path, making the command line much more user-friendly.
echo $PATH
# Expected output (example):
# /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin
Viewing the current $PATH variable.
$PATH permanently, you typically modify your shell's configuration file (e.g., ~/.zshrc for Zsh, ~/.bash_profile or ~/.bashrc for Bash). For example: export PATH="/new/directory:$PATH".What is $fpath?
The $fpath environment variable is specific to Zsh (Z Shell) and serves a similar purpose to $PATH, but exclusively for shell functions. It's an array of directories where Zsh looks for function definitions. When you call a function that hasn't been explicitly defined in your current shell session, Zsh searches these directories for a file with the same name as the function. If found, the file is sourced, and the function becomes available. This is particularly useful for autoloading functions, meaning functions are only loaded into memory when they are first called, improving shell startup performance.
echo $fpath
# Expected output (example):
# /usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/5.8/functions
Viewing the current $fpath variable in Zsh.
$PATH, which is a colon-separated string, $fpath is an array of strings. When modifying it, you append or prepend elements to the array, for example: fpath=(/new/function/dir $fpath).Key Differences and Interactions
The fundamental distinction lies in what they locate: $PATH finds executable binaries and scripts, while $fpath finds shell function definitions (primarily in Zsh). While both are crucial for shell operation, they operate on different types of 'commands'. A common scenario where this distinction matters is when you write a shell script that you want to be executable (placed in a $PATH directory) versus a collection of utility functions you want to be autoloaded by Zsh (placed in an $fpath directory).
flowchart TD
User[User types command] --> Shell(Shell process)
Shell --> CheckBuiltin{Is it a built-in command?}
CheckBuiltin -->|Yes| ExecuteBuiltin[Execute built-in]
CheckBuiltin -->|No| CheckAlias{Is it an alias?}
CheckAlias -->|Yes| ExpandAlias[Expand and re-evaluate]
CheckAlias -->|No| CheckFunction{Is it a defined function?}
CheckFunction -->|Yes| ExecuteFunction[Execute function]
CheckFunction -->|No| SearchFpath{Search $fpath (Zsh only)?}
SearchFpath -->|Yes| LoadFunction[Load function from $fpath]
LoadFunction --> ExecuteFunction
SearchFpath -->|No| SearchPath{Search $PATH?}
SearchPath -->|Yes| ExecuteBinary[Execute binary/script from $PATH]
SearchPath -->|No| CommandNotFound[Command not found error]Shell command lookup order, highlighting $PATH and $fpath roles.
The diagram above illustrates the typical command lookup order in a shell like Zsh. Notice how $fpath is consulted specifically for functions, while $PATH is reserved for external executables. This layered approach allows for flexible and efficient command resolution.