Right, so you’ve run ./configure and it’s asking you for a --prefix. Or maybe you’re just staring at a CMakeLists.txt wondering where this thing is going to end up. This isn’t just some trivial detail; this is you deciding where on your filesystem this new software will live, and that decision has serious consequences for how you manage your system. Get it wrong, and you’ll be living with a minor annoyance for the life of that application. Get it really wrong, and you might hose something important later.

The two heavyweight champions in this arena are /usr/local and /opt. Most configure scripts will default to /usr/local, which is a solid choice, but not always the best choice. Let’s break down why.

The Default: /usr/local

This is the traditional place for software you compile yourself, and its existence is a kind of truce between you and your system’s package manager. The idea is brilliantly simple: the /usr hierarchy is for your distribution’s package manager (apt, yum, dnf, pacman), and /usr/local is for you. The package manager knows to leave /usr/local the heck alone. It won’t overwrite your meticulously compiled nginx with its own older version, and it won’t come in and clean up files it doesn’t recognize.

When you do --prefix=/usr/local, the software installs itself in the standard Unix way, just scoped to that directory:

  • Binaries go to /usr/local/bin
  • Libraries go to /usr/local/lib
  • Headers go to /usr/local/include
  • Configuration files often go to /usr/local/etc

The huge advantage here is that almost every system’s default PATH and library paths (LD_LIBRARY_PATH or the paths in /etc/ld.so.conf) already include /usr/local/bin and /usr/local/lib. This means that once you make install, you can often just type the name of your new binary and it’ll run. No extra configuration needed. It feels native.

The downside? Organization, or lack thereof. If you install ten different programs to /usr/local, they all dump their files into the same bin, lib, and etc directories. It works, but it’s a bit of a melting pot. Uninstalling is a pain unless you used make install with a DESTDIR for a package or you remember to use checkinstall or make install --record-installed-files. Otherwise, you’re hunting through those directories trying to remember which files belong to which program. It’s… not fun.

The Neatnik’s Choice: /opt

If /usr/local is a shared toolshed, /opt (short for “optional”) is a warehouse with individual, self-contained units. The standard practice is to install each software package into its own subdirectory under /opt, like /opt/my_awesome_app. This package contains everything: its own bin, lib, etc, share right there in its own little home.

So you’d typically configure it like this:

./configure --prefix=/opt/varnish-7.3.0
# or for a more generic path you might symlink later
./configure --prefix=/opt/varnish

The advantage is glorious isolation. Everything for Varnish-7.3.0 is in /opt/varnish-7.3.0. Want to see what files it installed? ls /opt/varnish-7.3.0. Want to run it? Use the full path /opt/varnish-7.3.0/bin/varnishd. Want to completely remove it from your system without a trace? rm -rf /opt/varnish-7.3.0. It’s brutally simple and utterly clean.

The trade-off? Your shell has no idea where to find it. Nothing in /opt is in your default PATH. To make it usable, you have to do a bit of system integration yourself. The most elegant way is to symlink the binaries you need into a directory that is on your PATH, like /usr/local/bin (see how they can work together?).

sudo ln -s /opt/varnish-7.3.0/bin/varnishd /usr/local/bin/varnishd

Alternatively, you can add the specific package’s bin directory to your shell’s PATH in your .bashrc or similar, but I find symlinks more explicit and easier to manage.

So, Which One Should You Use?

Here’s the rule of thumb I’ve developed after years of compiling things I probably shouldn’t have:

  • Use /usr/local for utilities, smaller libraries, and things you want to behave like a first-class citizen on your system, available to every user without a second thought. wget, tmux, htop—these are all great candidates.
  • Use /opt for large, complex, or self-contained applications, or for when you need to manage multiple versions side-by-side. A specific version of nginx with custom modules, a new runtime like Julia, or a proprietary application you’ve extracted from a tarball—these all scream for /opt. It’s also the clear winner for anything you might want to remove cleanly later.

The designers of this system weren’t being questionable here; they were actually pretty smart. They gave you two distinct tools for two distinct jobs. The questionable choice would be ignoring them and doing --prefix=/usr. Don’t do that. You’ll overwrite your package manager’s files and the next time you run an update, well… let’s just say you’ll have a learning experience. Stick to /usr/local or /opt. Your future self, the one who isn’t trying to repair a broken system, will thank you.