Installing and uninstalling software (pkg and ports)

freebsd 15 / published / guide #28 / ≈ 6 min read

FreeBSD has two ways to install software, and the distinction trips up almost every Linux refugee at some point. They're not competing systems — they're two interfaces to the same software collection.

  • pkg — pre-compiled binary packages. Fast, simple, what you use 95% of the time. Like apt or pacman.
  • ports — the recipes those packages are built from. You compile them yourself, optionally with custom options. Slower, more flexible.

This guide covers both. If you're new, skim the ports section, lean on pkg for everything.

Part 1: pkg — the daily way

Bootstrap (only the first time)

A fresh FreeBSD ships with a tiny stub. The first run pulls in the real pkg:

sudo pkg bootstrap -y

Search for something

pkg search nginx                 # exact-ish substring match
pkg search -i Nginx              # case-insensitive
pkg search -gx "^nginx$"         # regex anchored at start/end
pkg search -D mariadb            # also show package descriptions

If you're not sure what something's called, search broadly first, then narrow.

Install

sudo pkg install nginx           # confirms, then installs
sudo pkg install -y nginx git    # multiple at once, skip the confirmation

pkg downloads the binary package, its dependencies, and lays everything down under /usr/local/. Config files go to /usr/local/etc/, service scripts to /usr/local/etc/rc.d/ (see the rc.conf guide for what those mean).

Find out about what's installed

pkg info                         # list every installed package
pkg info nginx                   # details for one
pkg info -l nginx                # every file it installed
pkg info -d nginx                # what depends on what
pkg which /usr/local/bin/curl    # which package owns this file?

pkg which is genuinely useful: when something's on your filesystem and you don't know how it got there, this tells you.

Upgrade everything

sudo pkg update                  # refresh the catalogue (rarely needed manually)
sudo pkg upgrade                 # apply available updates

It's safe to run pkg upgrade regularly — pkg always shows you what it's about to do and waits for confirmation.

Check for security issues

sudo pkg audit -F

The -F fetches the latest vulnerability database first, then prints any installed packages with known issues. Good to run once in a while; FreeBSD's daily periodic emails will remind you.

Remove

sudo pkg delete nginx                  # remove one package
sudo pkg delete -y nginx mariadb103    # several at once, no prompt

Dependencies that were pulled in only for the package you're deleting are left behind. Sweep them up afterwards:

sudo pkg autoremove

That removes any "leaf" dependencies nothing else needs anymore — equivalent to Arch's pacman -Rns $(pacman -Qdtq).

Pin a package so it doesn't update

Sometimes you don't want an upgrade for a specific package (a kernel module, a database during a release):

sudo pkg lock nginx
sudo pkg unlock nginx
pkg lock -l                       # list everything currently locked

Clean the cache

sudo pkg clean                    # remove cached downloads

Quarterly vs Latest

By default, FreeBSD points pkg at the "quarterly" repo — a snapshot taken every three months that only receives security and major-bug fixes. If you'd rather track the latest versions of everything (closer to Arch's pace), edit /usr/local/etc/pkg/repos/FreeBSD.conf (create the file if it's missing):

FreeBSD: {
    url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
}

Then:

sudo pkg update -f
sudo pkg upgrade

Switch back by changing latest to quarterly the same way. Most production servers stay on quarterly; desktops sometimes prefer latest.

Part 2: ports — the from-source way

The ports tree is a giant directory of build recipes — one per piece of software. When you install via ports, FreeBSD downloads the source, applies its patches, and compiles for your machine. Slow, but it lets you change compile-time options that the pre-built package was forced to pick.

When you actually want ports:

  • A package was built without an option you need (e.g., Nginx without HTTP/3 support, or PostgreSQL without LLVM).
  • You want to apply a local patch.
  • You're running on an unusual architecture where binary packages aren't built.

For everything else, stick with pkg.

Get the ports tree

The modern way is git (the old portsnap was retired in 2024):

sudo pkg install git              # if you don't have git yet
sudo git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports

This drops about 1.5 GB into /usr/ports/. The --depth 1 means "skip the history" — much faster, and you don't need it.

Find a port

Every port lives at /usr/ports/<category>/<name>. The fastest way to find one:

cd /usr/ports
make search name=nginx
make search key=database         # search by keyword

Or just find if you know the name:

find /usr/ports -type d -name "nginx*"

Build and install

cd /usr/ports/www/nginx
sudo make install clean

What that does, in order:

  1. Downloads the source tarball.
  2. Pops up a config menu the first time, listing build options (TLS library choice, modules to include, etc.).
  3. Builds.
  4. Installs into /usr/local/, exactly like pkg would have.
  5. clean deletes the work directory afterwards.

Inspecting and tweaking build options

cd /usr/ports/www/nginx
make showconfig                   # see what's currently selected
make config                       # bring the menu back up to change them
make config-recursive             # same, but for every dependency too
make rmconfig                     # forget all customisations

Options live in /var/db/ports/<origin>/options if you ever want to see them as a file.

What just got installed?

Once a port builds and installs, it's recorded in the package database — same one pkg uses. So:

pkg info nginx

...works on a port-installed nginx exactly the same as a pkg-installed one. There's no separate ports database. This trips people up at first; the relief is realising you don't have to learn two parallel tool sets.

Remove a port-installed thing

sudo pkg delete nginx

Yes, really. Because the install registers with the package database, you uninstall the same way regardless of which path put it there. The old make deinstall works too, but pkg delete is shorter and consistent.

Update the ports tree

cd /usr/ports
sudo git pull

Pulls the latest recipes. Doesn't rebuild anything — for that you'd either re-run make install clean in each port's directory, or use a helper:

sudo pkg install portmaster
sudo portmaster -a               # update everything installed from ports

portmaster automates the rebuild dance. For serious port users running many machines, poudriere is the heavyweight option — it builds packages in clean jails. Most people don't need it.

Part 3: mixing pkg and ports (it's fine, mostly)

You can install some things from pkg and others from ports on the same machine. Two things to know:

  • If a port and a package both exist, they'll fight: an upgrade via pkg might replace your custom-built port. Use pkg lock on the ones you built yourself.
  • If you switched the quarterly/latest repo, pkg upgrades might pull in a newer version of a dependency than your port was built against. Rebuild the port if anything breaks.

The cleanest split for a real machine: pkg for everything by default, ports for the one or two things you have specific needs about.

The shortest summary

  • pkg install foo — install a binary package.
  • pkg delete foo — uninstall.
  • pkg autoremove — clean orphaned dependencies.
  • pkg upgrade — update everything.
  • git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports — get the ports tree.
  • cd /usr/ports/category/name && sudo make install clean — build from source.
  • Both paths produce the same kind of installed package — manage with pkg commands regardless.

← back to index