Skip to content
elephantoo

Package management: apt, dnf & snap

Lesson 18 of 31 15 min read

Install, update and remove software, manage repositories, and use dpkg, rpm, Snap and Flatpak.


On Linux you rarely download installers from websites. Instead, software comes as packages from your distribution's repositories, which are curated, signed collections of thousands of programs. A package manager downloads them, resolves dependencies (other packages they need), installs files to the right places, and later updates or removes everything cleanly.

FamilyDistrosPackage formatLow-level toolHigh-level tool
DebianDebian, Ubuntu, Linux Mint, Pop!_OS.debdpkgapt
Red HatFedora, RHEL, Rocky, AlmaLinux, CentOS Stream.rpmrpmdnf
OthersArch (pacman), openSUSE (zypper), Alpine (apk)

Plus there are distro-independent formats: Snap, Flatpak and AppImage.

apt on Ubuntu and Debian#

Installing and removing software changes the system, so these commands need sudo:

Terminal
sudo apt update              # refresh the package lists from the repositories
sudo apt upgrade             # upgrade all installed packages
sudo apt install htop tree   # install one or more packages
sudo apt install -y curl     # -y answers "yes" to the confirmation (scripts, Dockerfiles)
sudo apt remove htop         # remove the package, keep its system-wide config files
sudo apt purge htop          # remove the package AND its config files
sudo apt autoremove          # remove dependencies nothing needs any more

A typical install looks like this:

Output
$ sudo apt install tree
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  tree
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 47.1 kB of archives.
After this operation, 111 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/universe amd64 tree amd64 2.1.1-2ubuntu3 [47.1 kB]
...
Setting up tree (2.1.1-2ubuntu3) ...

💡 Always update before install or upgrade. apt works from a local copy of the package lists. If that copy is old, you'll get old versions or "404 Not Found" errors.

apt upgrade never removes packages. sudo apt full-upgrade may remove or replace packages when dependencies change (that's what you want for big updates). Moving to a new release (e.g. Ubuntu 24.04 → 26.04) is a separate step: sudo do-release-upgrade.

Searching and inspecting (no sudo needed)

Terminal
apt search json processor    # search names and descriptions
apt show jq                  # description, version, size, dependencies
apt list --installed | less  # everything installed
apt list --upgradable        # what an upgrade would change (after apt update)
apt-cache policy rsync       # installed vs candidate version, and which repo
Output
$ apt-cache policy rsync
rsync:
  Installed: 3.5.0+ds1-0+deb13u1
  Candidate: 3.5.0+ds1-0+deb13u1
  Version table:
 *** 3.5.0+ds1-0+deb13u1 500
        500 http://deb.debian.org/debian trixie/main amd64 Packages
        100 /var/lib/dpkg/status

apt is the friendly interactive command. In scripts, apt-get and apt-cache have a stable output format, so you'll see apt-get install -y ... in Dockerfiles and CI.

dpkg: the low-level tool

dpkg works on individual .deb files and the database of installed packages:

Terminal
dpkg -l rsync               # is it installed? which version?
dpkg -L rsync | head -5     # files installed by a package
dpkg -S /usr/bin/rsync      # which package owns this file?
Output
ii  rsync          3.5.0+ds1-0+deb13u1 amd64        fast, versatile, remote (and local) file-copying tool
/.
/etc
/etc/default
/etc/default/rsync
/etc/init.d
rsync: /usr/bin/rsync

(dpkg -l also prints a header, which is omitted here. ii means "desired: install, status: installed".)

To install a downloaded .deb, use apt with a path so dependencies get resolved too:

Terminal
sudo apt install ./google-chrome-stable_current_amd64.deb

(sudo dpkg -i file.deb also works, but leaves missing dependencies for you to fix with sudo apt -f install.)

Repositories#

apt's sources are listed in /etc/apt/sources.list.d/. Modern Ubuntu (24.04+) and Debian 13 use the deb822 format, like /etc/apt/sources.list.d/ubuntu.sources:

/etc/apt/sources.list.d/ubuntu.sources
Types: deb
URIs: http://archive.ubuntu.com/ubuntu
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Ubuntu's components are main (supported by Canonical), universe (community), restricted (proprietary drivers) and multiverse (non-free). Debian uses main, contrib, non-free and non-free-firmware.

Adding a third-party repository

Vendors like Docker, PostgreSQL, Node.js (NodeSource) and Microsoft publish their own repos. The modern, safe pattern is to download the vendor's signing key to /etc/apt/keyrings/ and reference it with signed-by, so that key is trusted only for that repo:

Terminal
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update && sudo apt install docker-ce

Always follow the vendor's current official instructions; the URLs above are Docker's. On Ubuntu, PPAs (Personal Package Archives) are added with sudo add-apt-repository ppa:owner/name.

⚠️ Every repository you add can install software as root on your machine. Only add sources you trust, and avoid the old apt-key add method (it trusted the key for all repos and is deprecated).

Keeping a version: holds

Terminal
sudo apt-mark hold mysql-server     # don't upgrade this package
apt-mark showhold
sudo apt-mark unhold mysql-server

Automatic security updates

Ubuntu servers ship with unattended-upgrades, which installs security updates automatically. Configure it with sudo dpkg-reconfigure unattended-upgrades. On Debian, install it with sudo apt install unattended-upgrades.

dnf on Fedora, RHEL, Rocky and AlmaLinux#

dnf mirrors apt closely. Fedora 41+ ships dnf5, which is faster but uses the same commands:

TaskDebian/UbuntuFedora/RHEL
Refresh metadatasudo apt updateautomatic (or sudo dnf makecache)
Upgrade everythingsudo apt upgradesudo dnf upgrade
Installsudo apt install pkgsudo dnf install pkg
Removesudo apt remove pkgsudo dnf remove pkg
Searchapt search worddnf search word
Detailsapt show pkgdnf info pkg
Which package has a file?dpkg -S /pathrpm -qf /path
Which package provides a command (not installed)?apt-file search bin/cmddnf provides /usr/bin/cmd
Files in a packagedpkg -L pkgrpm -ql pkg
List installedapt list --installeddnf list --installed
History / undo/var/log/apt/history.logdnf history, dnf history undo N

Repos live in /etc/yum.repos.d/*.repo. On RHEL-family servers you'll often enable EPEL (Extra Packages for Enterprise Linux): sudo dnf install epel-release.

Snap and Flatpak#

These formats bundle an app with its dependencies, run it in a sandbox, and work across distributions:

Terminal
# Snap (preinstalled on Ubuntu)
snap find spotify
sudo snap install code --classic     # --classic = less sandboxing, needed by IDEs
snap list
sudo snap refresh                    # snaps also auto-update in the background
sudo snap remove code

# Flatpak (preinstalled on Fedora Workstation; apps come from Flathub)
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install flathub org.gimp.GIMP
flatpak run org.gimp.GIMP
flatpak update

When to use what:

  • Server tools and libraries (nginx, PostgreSQL, git, Python): use the native package manager.
  • Desktop apps you want in their latest version (browsers, editors, chat apps): Flatpak or Snap are great.
  • Language libraries (Python, Node.js packages): use the language's own tool inside a project (pip in a virtual environment, npm), not sudo pip install. Modern Ubuntu and Debian block system-wide pip install with an "externally-managed-environment" error for exactly this reason.

Common mistakes#

  • Forgetting sudo apt update and then wondering why a package can't be found or is out of date.
  • Mixing package sources for the same software (e.g. the distro's nodejs plus a NodeSource repo plus a snap), which leaves several versions fighting over PATH.
  • Installing random .deb/.rpm files from the web. Prefer the official repo or the vendor's signed repository.
  • Interrupting an upgrade. If apt says "Could not get lock /var/lib/dpkg/lock-frontend", another apt process (often unattended-upgrades) is running. Wait for it; don't delete the lock files. If an upgrade really was interrupted, run sudo dpkg --configure -a.
  • Using sudo pip install to install system-wide Python packages. Use python3 -m venv or pipx.

What's next#

Installed software runs as processes. Next you'll learn to inspect them, send them signals and control jobs in your terminal.

Check your understanding

Quick quiz

0/3 answered
  1. 1.On Ubuntu, what is the difference between apt update and apt upgrade?

  2. 2.Which command shows which installed package a file belongs to on Debian/Ubuntu?

  3. 3.What is the Fedora/RHEL equivalent of sudo apt install nginx?

Finished reading?

Mark this lesson complete to track your progress.