Chapter Eleven

Package Management

In the early days of Unix, installing a new program meant downloading a tarball, extracting it, running ./configure && make && make install, and crossing your fingers. It worked, but it was tedious, it scattered files across the system with no record of what came from where, and uninstalling was often just "try to remember what got put where". Package management was invented to fix this. Today, every serious Linux distribution ships with a package manager, and it is the tool you will use most often as an administrator after the shell itself.

Learning Objectives
  1. Explain why packages exist and what problems they solve
  2. Use apt, dnf, and pacman confidently for everyday tasks
  3. Compare traditional package managers with newer sandboxed formats
  4. Install software from source when no package is available
  5. Recognise and avoid the symptoms of dependency hell

Why Packages?

A package is a single archive file that bundles together everything an installable piece of software needs: its binaries, libraries, configuration files, documentation, default settings, and, crucially, metadata. The metadata describes the package's name and version, lists its dependencies (other packages it needs to work), specifies which files it installs and where, and includes pre- and post-install scripts that can configure the system or start services.

With this metadata, a package manager can do things that manual installation cannot:

  • Track every file installed on the system and what package owns it.
  • Resolve dependencies automatically, installing prerequisites when you ask for a package.
  • Upgrade packages cleanly, preserving your configuration files.
  • Roll back or remove software completely, without orphaned files.
  • Verify the integrity of installed files with checksums.
  • Apply security updates across the whole system in one command.

Think of a package manager as a database of everything installed, plus a network of remote repositories holding the available packages, plus the machinery to keep the two in sync. The effect is transformative: on a Linux machine, applying a year's worth of security fixes to every installed program can be a single command.

The Two Main Families

Most Linux distributions trace their package format to one of two traditions.

Debian and its descendants (Ubuntu, Linux Mint, Raspberry Pi OS, Pop!_OS) use the .deb format, with dpkg as the low-level tool and apt as the high-level front end.

Red Hat and its descendants (Fedora, RHEL, CentOS Stream, Rocky, AlmaLinux) use the .rpm format, with rpm as the low-level tool and dnf (previously yum) as the high-level front end.

openSUSE also uses the .rpm format and is therefore often grouped with the Red Hat family for convenience, but its lineage is independent: SUSE was founded in Germany in 1994, originally based on Slackware, and has always evolved alongside Red Hat rather than from it. Its high-level front end is zypper.

These three traditions cover more than 90% of Linux installations. A few distributions, such as Arch, Alpine, Gentoo, and Void, use their own formats, which are worth knowing but rarer in production.

apt: The Debian Way

On Debian and Ubuntu, apt is the command you will use daily. It replaced the older apt-get and apt-cache commands around 2014 with a friendlier, more colourful interface.

sudo apt update                 # refresh the package list from repositories
sudo apt upgrade                # upgrade all installed packages
sudo apt install nginx          # install a package
sudo apt install nginx=1.22.0-1 # install a specific version
sudo apt remove nginx           # remove, leaving config files
sudo apt purge nginx            # remove, including config files
sudo apt autoremove             # remove unused dependencies
apt search webserver            # search available packages
apt show nginx                  # detailed info about a package
apt list --installed            # list installed packages

The distinction between update and upgrade trips up newcomers. update refreshes the local cache of what is available; upgrade actually installs the newer versions. You almost always run update before upgrade.

The underlying tool is dpkg, which operates on individual .deb files:

sudo dpkg -i package.deb        # install a .deb file
sudo dpkg -r package            # remove
dpkg -l                         # list installed
dpkg -L nginx                   # list files owned by a package
dpkg -S /etc/nginx/nginx.conf   # which package owns this file?

dpkg does not handle dependencies by itself; if you dpkg -i a package with missing dependencies, it will complain. Running sudo apt install -f (for "fix broken") resolves the missing pieces.

Repositories are configured in /etc/apt/sources.list and /etc/apt/sources.list.d/*.list. Each line points to a mirror carrying packages for a particular distribution and component (main, contrib, non-free, universe, multiverse). Adding a third-party repository, for Docker, Node.js, or Kubernetes, is a matter of dropping a .list file and an accompanying GPG key.

Table 11.1: Common apt commands

Command Purpose
apt update Refresh package lists
apt upgrade Install available upgrades
apt full-upgrade Upgrade, removing packages if needed
apt install pkg Install a package
apt remove pkg Remove (keep config files)
apt purge pkg Remove + wipe config
apt autoremove Remove orphaned dependencies
apt search pat Search package descriptions
apt show pkg Show details about a package
apt list --installed List installed packages
apt policy pkg Show which repo versions are available

dnf: The Red Hat Way

On Fedora and its downstream cousins, dnf is the command.

sudo dnf check-update           # refresh and show available updates
sudo dnf upgrade                # install all available updates
sudo dnf install nginx          # install a package
sudo dnf remove nginx           # remove
sudo dnf autoremove             # remove unused dependencies
dnf search webserver            # search
dnf info nginx                  # detailed info
dnf list installed              # list installed
dnf history                     # see every transaction ever performed

The last one is a nice touch: dnf history gives you a chronological log of every install, upgrade, or removal, with the ability to roll back a specific transaction.

Underneath, dnf uses rpm for low-level operations:

sudo rpm -i package.rpm         # install
sudo rpm -e nginx               # erase (remove)
rpm -qa                         # query all installed
rpm -qf /etc/nginx/nginx.conf   # which package owns this file?
rpm -ql nginx                   # list files in this package

Repositories live in /etc/yum.repos.d/*.repo. Adding a new repository, like RPM Fusion for multimedia codecs, means placing a new .repo file there.

Table 11.2: Common dnf commands

Command Purpose
dnf install pkg Install a package
dnf remove pkg Uninstall
dnf upgrade Upgrade everything
dnf search pat Search
dnf info pkg Package details
dnf list --installed List installed
dnf provides /path/to/file Which package owns this file?
dnf history View transaction history
dnf history undo N Roll back transaction N
dnf group install 'Group Name' Install a package group

Arch and pacman

Arch Linux and its derivatives (Manjaro, EndeavourOS) use pacman, one of the fastest and most elegant package managers around.

sudo pacman -Syu                # sync, refresh, upgrade (do this often)
sudo pacman -S nginx            # install
sudo pacman -R nginx            # remove
sudo pacman -Rs nginx           # remove and unused dependencies
pacman -Ss nginx                # search
pacman -Q                       # list installed
pacman -Qi nginx                # info about an installed package

The -Syu invocation, for Sync/refresh-Y/Upgrade, is the daily Arch ritual. Arch is a rolling release distribution, meaning there are no version numbers or release cycles. You simply upgrade whenever you feel like it, always receiving the latest upstream versions.

The AUR (Arch User Repository) deserves a mention. It is not a traditional binary repository but a collection of community-maintained build scripts (called PKGBUILDs) for software not in the official repositories. Tools like yay or paru automate fetching, building, and installing from the AUR. It is one of the largest informal software collections in Linux, but because the scripts are community-maintained, you should read before running.

Table 11.3: pacman cheat sheet

Command Purpose
pacman -Syu Sync database and upgrade everything
pacman -S pkg Install a package
pacman -Rs pkg Remove + unused dependencies
pacman -Qs pat Search installed packages
pacman -Ss pat Search all repos
pacman -Qi pkg Info about installed package
pacman -Qo /path Which package owns this file?
pacman -Ql pkg List files owned by pkg
pacman -Qdt Orphaned packages

openSUSE and zypper

openSUSE uses zypper, an apt-style tool operating on RPM packages:

sudo zypper refresh
sudo zypper update
sudo zypper install nginx
sudo zypper remove nginx
zypper search nginx

If you can drive apt, zypper feels familiar within an hour.

The New Wave: Snap, Flatpak, AppImage

Traditional package managers install software system-wide and share libraries across packages, which is efficient but inflexible: everything must use the same version of a library at the same time. A new wave of formats trades efficiency for independence.

Snap, developed by Canonical, packages applications with all their dependencies into a single squashfs image, confined by AppArmor profiles. Snaps are automatically updated and work across distributions. They are the default for several Ubuntu desktop applications.

snap find vlc
sudo snap install vlc
snap list
sudo snap remove vlc

Flatpak is an alternative designed with desktop applications in mind, widely used on Fedora and promoted by GNOME. Flatpaks run in sandboxes based on bubblewrap, with fine-grained portals for accessing the filesystem, camera, printer, and so on. The central repository is Flathub.

flatpak install flathub org.videolan.VLC
flatpak run org.videolan.VLC
flatpak list
flatpak update

AppImage is the simplest of the three: a single executable file that contains the application and all its dependencies. You download it, make it executable, and run it. No installation, no root, no package manager involved.

chmod +x MyApp.AppImage
./MyApp.AppImage

Each of these formats has its champions and its critics. The pragmatic view is that traditional packages are best for system software and command-line tools, while sandboxed formats shine for desktop applications that need to run the same on many distributions.

Table 11.4: Universal packaging formats

Format Sandboxing Runtime Store Notes
Snap AppArmor / seccomp Bundled snaps Snap Store (central) Canonical-controlled
Flatpak Bubblewrap / Portals Shared runtimes Flathub (decentralised) Community favourite
AppImage None (by default) Bundled in file No central store Single-file, portable
Native (.deb/.rpm) None System shared libs Distro repos Smallest footprint

Building from Source

Occasionally a program you need is not packaged anywhere, or you need a newer version than the repositories carry. The classic Unix dance is:

tar xzf myapp-1.2.3.tar.gz
cd myapp-1.2.3
./configure --prefix=/usr/local
make
sudo make install

The ./configure script probes your system for libraries and compilers and generates a Makefile. make compiles. make install copies the results into place. Modern projects increasingly use CMake or Meson in place of autoconf, so the incantation varies slightly, but the idea is the same.

When installing software from source, prefer /usr/local as the prefix rather than /usr. This keeps source-installed software separate from package-managed software, so they never fight over the same files. Better still, use checkinstall to build a quick .deb or .rpm that the package manager can track.

Dependency Hell

A package manager exists largely to solve dependency hell: the nightmare where package A needs library X version 2, package B needs library X version 3, and library X can only exist once on the system. A good package manager will refuse to install a conflicting combination and tell you why. The bad cases usually occur when you mix repositories that target different distribution versions, or when you install from source over a package-managed library.

The best defences against dependency hell are:

  1. Stick to your distribution's official repositories when possible.
  2. Use sandboxed formats (Snap, Flatpak) for applications that need newer libraries than your base system.
  3. Use containers (Chapter 17) for development environments that need exotic or conflicting dependencies.
  4. If you must install third-party software, prefer packages from the upstream vendor (e.g. Docker's own Debian repository) over random instructions from the internet.

Table 11.5: How different systems avoid dependency hell

Approach Strategy Cost
Stable distros (Debian, RHEL) Freeze a set of versions that all cooperate Software is 'old'
Rolling (Arch) Always ship the latest, in lockstep Occasional breakage
Flatpak/Snap Bundle entire runtime with each app Larger downloads
Containers (Docker) Bundle the whole userland per service Image bloat
Nix / NixOS Content-addressed, side-by-side versions Steep learning curve

A Package Manager Cheat Sheet

Memorise the ones for your distribution. Look up the others when you encounter them. Package management is where most routine Linux administration happens, and fluency here pays back quickly.

Table 11.6: Package manager comparison

Manager Family Format Install Update DB Upgrade All
apt Debian/Ubuntu .deb apt install pkg apt update apt upgrade
dnf Fedora/RHEL .rpm dnf install pkg (automatic) dnf upgrade
pacman Arch .pkg.tar.zst pacman -S pkg pacman -Sy pacman -Syu
zypper openSUSE .rpm zypper in pkg zypper ref zypper up
apk Alpine .apk apk add pkg apk update apk upgrade
emerge Gentoo ebuild (source) emerge pkg emerge --sync emerge -uDN @world
Textbook of Linux — Learn Linux on iPhone — Download on the App Store

Frequently Asked Questions

  1. What exactly is a software package?
  2. What is a repository and how does the package manager use it?
  3. What is the difference between dpkg and rpm?
  4. What is the difference between apt and apt-get?
  5. What is the difference between dnf and yum?
  6. What makes pacman different from apt and dnf?
  7. How does the package manager know a package is genuine? What is GPG signing?
  8. What is a dependency, and how does the package manager resolve them?
  9. What is dependency hell and how do package managers avoid it?
  10. What does semantic versioning mean for Linux packages?
  11. How do I stop a package from being upgraded?
  12. What lives in /var/lib/dpkg and /var/lib/rpm?
  13. What is the difference between Snap, Flatpak, and AppImage?
  14. Why do different distributions use different package managers?
  15. What is the AUR, and how do PPAs and COPR compare?
  16. What is a source-based distribution like Gentoo?
  17. When should I build from source instead of using a package?
  18. Why aren't pip, cargo, and npm system package managers?
  19. What is /etc/apt/sources.list and how do I add a third-party repository safely?
  20. How do unattended security updates work, and should I enable them?