In a *nix environment (Linux, MacOS, WSL), software without packages can sometimes install to global spaces by default. This is often undesirable, due to running unverified scripts as root, conflicts with other packages, and potentially breaking the software during an OS upgrade. Instead, these custom installs should be placed in your home directory. In my case,
/Users/fritzy on MacOS.
But where in your $HOME? As the title implies,
This directory is a GNOME convention that other software has adopted as well. Similar to
/usr/local, it is designated for custom or non-package installed software. The
. at the beginning of the directory name has the added benefit of hiding the directory, preventing cluttering an often-used space.
If it doesn't exist, go ahead and create it, along with a
bin directory as your user. No special permissions are needed.
mkdir -p $HOME/.local/bin
Then, make sure that
$HOME/.local/bin is in your $PATH, preferably with a higher priority than
For Linux Bash users do:
echo PATH=$HOME/local.bin:\$PATH >> $HOME/.bashrc
Now we can install some software. I wanted to install Starship, a cross-shell prompt in my WSL2 Ubuntu. The only documented way to install this is to install by directly executing a download -- questionable from a security perspective.
curl -fsSL https://starship.rs/install.sh | bash
Instead, I downloaded and inspected the script. I discovered a few things. By default, it would install to
/usr/bin, a global space requiring root access. But there was good news; I found a command-line option to set the install directory.
curl https://starship.rs/install.sh --output install.sh # download chmod +x install.sh # make it executable ./install.sh -b $HOME/.local/bin # the -b option is what discovered rm ./install.sh # don't need this anymore
I then followed the instructions for setting up Starship for Bash.
echo 'eval "$(starship init bash)"' >> $HOME/.bashrc
If you build custom software, you'll want to find the "prefix" option, and set it to
$HOME/.local. When following build instructions, you should ignore anything that tells you to use
sudo when installing; you won't need it with a prefix in your home directory, and doing so may cause problems later.
Let's clone Node.js, compile it, and install it to our
cd ~/build # I use a build directory for custom compiling git clone firstname.lastname@example.org:nodejs/node.git cd node
git fetch --all --tags # update fetched branches and tags git tag # lists tags
As an aside, if you want to sort tags with semver logic, you can update your git config.
git config --global tag.sort version:refname
git checkout tags/v15.8.0 -b build-v15.8.0
Now we can compile it.
./configure --prefix=$HOME/.local make -j12 # number of hardware thread on my cpu make install # sets everything up in your prefix directory
make line will take a bit, but hey, you look really busy and smart when you're compiling code.
Now when you run
node -V, it'll show your newly install Node.js version. You also now have the added benefit of being able to install 'global' npm packages without sudo. You'll notice that you now have
share directories in your
$HOME/.local, just like you would with a
You can get similar benefits of using nvm without having to compile.
Installing unpackaged software in your
$HOME/.local directory is more secure, more stable across OS upgrades, and prevents unnecessary
root usage going forward. It can take a bit of investigation with some software, but is worth having a cleaner install in the end. Ideally, the vast majority of your software simply uses OS supported packages, but now you have a plan for when it doesn't.
For you MacOS users, OS upgrades would regularly break Brew for me, but you can even install Brew into your home directory.
Please comment below, or send me your thoughts on Twitter @fritzy.