Linux Package Management: apt, dnf, Snap and Flatpak
Install, update and remove software on Ubuntu, Debian, Fedora and RHEL with apt and dnf, add third-party repositories safely, and use Snap and Flatpak.
On Windows and macOS you often download an installer from a vendor's website. On Linux, you ask the package manager. It downloads software from your distribution's repositories, checks the signatures, installs everything the program depends on, and later updates all of it with one command. Security fixes for your web server, your SSH daemon and your kernel all arrive the same way.
This part covers apt on Ubuntu and Debian and dnf on Fedora and RHEL in depth, then the other package managers, Snap and Flatpak, and the mistakes that break systems.
Prerequisites
The apt output below comes from a fresh Ubuntu 24.04.5 LTS image and the dnf output from a Fedora 44 image (dnf5 5.4.3). Both ran on an arm64 machine, so Ubuntu downloads from ports.ubuntu.com and package names end in arm64 or aarch64. On a typical x86 PC or cloud server, you see archive.ubuntu.com, security.ubuntu.com and amd64 instead. Versions and sizes change with every update.
How Package Management Works
- A package is an archive with the program's files, metadata (name, version, description) and a list of dependencies: other packages it needs.
- A repository is a server that publishes packages plus a signed index of everything it offers. Your system trusts a repository through its signing key.
- The high-level tool (
apt,dnf) reads the index, works out the dependencies, downloads the packages and checks their signatures. The low-level tool (dpkg,rpm) installs a single package file and records what it installed.
| Family | Distributions | Package format | High-level tool | Low-level tool |
|---|---|---|---|---|
| Debian | Debian, Ubuntu, Linux Mint, Pop!_OS | .deb |
apt (apt-get in scripts) |
dpkg |
| Red Hat | Fedora, RHEL, Rocky Linux, AlmaLinux, CentOS Stream, Amazon Linux | .rpm |
dnf (yum is an alias) |
rpm |
| SUSE | openSUSE, SUSE Linux Enterprise | .rpm |
zypper |
rpm |
| Arch | Arch Linux, Manjaro | .pkg.tar.zst |
pacman |
pacman |
| Alpine | Alpine Linux (common in containers) | .apk |
apk |
apk |
Use the package manager of your distribution, and only repositories built for your exact release.
apt on Ubuntu and Debian
Where Packages Come From
Current Ubuntu releases describe their repositories in the deb822 format, one file per source, in /etc/apt/sources.list.d/. The old one-line /etc/apt/sources.list only holds a pointer now:
Each stanza lists the URL, the suites (noble is the codename of 24.04; -updates and -security carry fixes; -backports newer versions), the components (main is supported by Canonical, universe by the community, restricted and multiverse hold non-free software) and the key that signs it. On Debian 13 ("trixie") the components are main, contrib, non-free and non-free-firmware. Debian 13 still writes the one-line format during installation:
deb http://deb.debian.org/debian trixie main non-free-firmware
deb http://security.debian.org/debian-security trixie-security main non-free-firmware
deb http://deb.debian.org/debian trixie-updates main non-free-firmware
The one-line format still works. apt 3.0, which ships with Debian 13, has sudo apt modernize-sources to convert old files to deb822.
Update the Index and See What Can Be Upgraded
apt update downloads the current index from every repository. It installs nothing. Run it before you install or upgrade anything:
To install the upgrades:
sudo apt upgrade # upgrade installed packages, never remove any
sudo apt full-upgrade # also remove or replace packages when an upgrade needs it
apt upgrade lists what it will do and asks before it starts. Ubuntu rolls out some updates gradually (phased updates), so you may see "The following upgrades have been deferred due to phasing"; they arrive within a few days. If a kernel or core library was updated, the file /var/run/reboot-required appears and the login message says a reboot is needed.
Search and Inspect Packages
apt policy (also apt-cache policy) is the command to run when you wonder why apt picks a certain version: it lists every version it knows, the repository each comes from, and the priority that decides between them.
Install Packages
jq needed two libraries, so apt installed them too and marked them as automatically installed. Without -y, apt shows the plan and asks Do you want to continue? [Y/n]. Read that list, especially lines that say "REMOVED".
Ask dpkg what a package installed, and which package owns a file:
ii in the first column means the package is installed and configured. rc means it was removed but its configuration files are still on disk.
Remove Packages and Clean Up
apt removedeletes the program but keeps its configuration in/etc.apt purgedeletes the configuration too.apt autoremoveremoves dependencies nothing needs any more, here the two librariesjqpulled in.apt-mark holdstops a package from being upgraded, for example a database server you upgrade by hand. Remember tounholdit, or it never gets security fixes.sudo apt cleandeletes downloaded package files from/var/cache/apt/archiveswhen you need the disk space.
To install a .deb file you downloaded, give apt the path (with ./), so it also installs the dependencies: sudo apt install ./package.deb. Plain dpkg -i does not resolve dependencies.
apt is meant for people at a terminal; its output format may change between versions. In scripts and Dockerfiles, use apt-get, which has a stable interface, and run apt-get update in the same step as apt-get install -y --no-install-recommends ... so you never install from an old index.
Add a Third-Party Repository the Modern Way
Some software comes from the vendor's own repository: Docker, HashiCorp, Kubernetes, PostgreSQL, Node.js and many more. Older tutorials add the vendor's key with apt-key add. Do not follow them: apt-key trusted the key for every repository on the system, it was deprecated for years, and Debian 13 and Ubuntu 25.04 and later no longer ship it.
The current method stores the key in its own file and references it with Signed-By, so the key can only sign packages from that one repository. These are Docker's official instructions for Ubuntu, which use a deb822 .sources file:
The new repository shows up in apt update, and apt policy shows the candidate version from it. From here, sudo apt install docker-ce would install Docker from Docker's repository, and apt upgrade keeps it updated. The Docker guide continues from this point.
A few rules for third-party repositories:
- Every repository you add can install code that runs as root on your machine. Add only vendors you trust, and only over HTTPS.
- Check that the vendor supports your release. A repository for an older codename may install packages built against libraries you do not have.
- Store keys in
/etc/apt/keyrings/(your own) and reference them withSigned-By. Packages that ship their own keys use/usr/share/keyrings/. - PPAs (Personal Package Archives on Launchpad) are third-party repositories too.
sudo add-apt-repository ppa:owner/name(from thesoftware-properties-commonpackage) adds the source and its key in one step.
Python, pip and "externally-managed-environment"
Since Debian 12 and Ubuntu 23.04, pip install outside a virtual environment stops with an error. That protects the Python packages your system tools depend on from being overwritten:
Install Python libraries that a system tool needs with apt (sudo apt install python3-requests). For your own projects, create a virtual environment with python3 -m venv .venv (install python3-venv first on Ubuntu) and run pip inside it. For command-line tools written in Python, use pipx install <tool>. Avoid --break-system-packages unless you understand what it can break.
dnf on Fedora, RHEL, Rocky and AlmaLinux
Fedora 41 and later use DNF5, a rewrite in C++. RHEL 10, Rocky Linux 10 and AlmaLinux 10 still use DNF 4. Everyday commands are the same in both; the differences are in output and in a few subcommands such as config-manager. On RHEL and its rebuilds, yum is a link to dnf.
Repositories are .repo files in /etc/yum.repos.d/:
Install, query and remove a package:
Add a third-party repository by downloading its .repo file. The config-manager syntax changed in DNF5:
On RHEL 10 and its rebuilds (DNF 4), the same step is sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo, which needs the dnf-plugins-core package. dnf imports the repository's GPG key the first time you install from it and asks you to confirm the fingerprint; compare it with the one the vendor publishes.
apt and dnf Side by Side
| Task | Ubuntu / Debian | Fedora / RHEL |
|---|---|---|
| Refresh the index | sudo apt update |
automatic (sudo dnf makecache to force it) |
| Upgrade everything | sudo apt upgrade |
sudo dnf upgrade |
| List available upgrades | apt list --upgradable |
dnf check-upgrade |
| Install | sudo apt install pkg |
sudo dnf install pkg |
| Remove | sudo apt remove pkg |
sudo dnf remove pkg |
| Remove unused dependencies | sudo apt autoremove |
sudo dnf autoremove |
| Search | apt search word |
dnf search word |
| Details | apt show pkg |
dnf info pkg |
| Which package owns a file | dpkg -S /path |
rpm -qf /path |
| Which package provides a missing file | apt-file search name |
dnf provides '*/name' |
| Files in a package | dpkg -L pkg |
rpm -ql pkg |
| Hold a version | sudo apt-mark hold pkg |
sudo dnf versionlock add pkg |
| History and undo | /var/log/apt/history.log |
dnf history list, sudo dnf history undo <id> |
| Install a group of packages | sudo apt install build-essential |
sudo dnf group install development-tools |
| Automatic security updates | unattended-upgrades (on by default on Ubuntu) |
dnf5-plugin-automatic (Fedora), dnf-automatic (RHEL 10) |
On RHEL 10, dnf versionlock and dnf provides work as shown, and versionlock needs the python3-dnf-plugin-versionlock package. Group names differ between distributions, so run dnf group list first.
Other Package Managers
| Task | openSUSE (zypper) |
Arch (pacman) |
Alpine (apk) |
|---|---|---|---|
| Refresh and upgrade | sudo zypper refresh && sudo zypper update |
sudo pacman -Syu |
apk update && apk upgrade |
| Install | sudo zypper install pkg |
sudo pacman -S pkg |
apk add pkg |
| Remove | sudo zypper remove pkg |
sudo pacman -Rs pkg |
apk del pkg |
| Search | zypper search word |
pacman -Ss word |
apk search word |
On Arch, always upgrade the whole system with pacman -Syu before installing; pacman -Sy pkg on its own (a partial upgrade) can leave libraries out of step. In Alpine-based container images, use apk add --no-cache pkg so the index does not stay in the image.
Snap, Flatpak and AppImage
These formats bundle an application with its dependencies, so one build runs on many distributions. They are most useful for desktop applications and for tools that need a newer version than your distribution ships.
- Snap is Canonical's format with a central store. Snaps run confined and update automatically, which is convenient on desktops and surprising on servers; control the timing with
sudo snap refresh --holdorsnap set system refresh.timer=.... - Flatpak targets desktop applications, mostly from Flathub, and runs them in a sandbox.
- AppImage is a single executable file. It does not update itself and is not checked by any package manager, so download it only from the project's own site.
On servers, prefer your distribution's packages or the vendor's official repository. They get security updates through the same apt upgrade or dnf upgrade as everything else.
Building From Source
When software is not packaged, the classic build is:
sudo apt install build-essential # compilers and make (Fedora: sudo dnf group install development-tools)
./configure --prefix=/usr/local
make
sudo make install
Installing into /usr/local keeps your files apart from the distribution's. The package manager does not know about them, so it will not update or remove them, and nothing tells you about security fixes. For anything you run in production, a package, a vendor repository or a container image is easier to keep patched.
Troubleshooting
"Could not get lock /var/lib/dpkg/lock-frontend". Another apt process is running, often unattended-upgrades right after boot. Wait for it to finish (ps aux | grep -E 'apt|dpkg'). Do not delete the lock files.
"NO_PUBKEY" or "The following signatures couldn't be verified". The repository's key is missing or expired. Download the current key from the vendor's documentation into /etc/apt/keyrings/ and check that the Signed-By path in the .sources file matches.
"Unmet dependencies" or a half-finished install. Run sudo apt --fix-broken install, then sudo dpkg --configure -a if dpkg was interrupted.
"The following packages have been kept back". On Ubuntu this is usually a phased update; wait. Otherwise the upgrade needs to add or remove packages, which sudo apt full-upgrade allows after you review the list.
404 errors for an old release. Releases that reached end of life move to old-releases.ubuntu.com (Ubuntu) or archive.debian.org (Debian). Upgrade to a supported release instead of pointing at the archive.
dnf: "Error: GPG check FAILED". The package was not signed with a key dnf trusts. Import the vendor's key (sudo rpm --import <url>) after you have checked its fingerprint. Do not set gpgcheck=0.
Common Mistakes
- Following
apt-keytutorials. Use a keyring file andSigned-Byas shown above. - Adding repositories for another distribution or release, for example a Debian repository on Ubuntu or a
jammyrepository onnoble. Dependencies break in ways that are hard to undo. - Piping a download into
sudo bashwithout reading the script first. - Skipping
apt updatebefore installing, and getting 404 errors for package versions the mirror has already replaced. - Holding packages and forgetting them. Check
apt-mark showholdordnf versionlock listduring upgrades. - Using
pip install --break-system-packagesinstead of a virtual environment.
Summary
- Packages come from signed repositories;
aptanddnfresolve dependencies,dpkgandrpminstall single files. - On Ubuntu and Debian:
apt update,apt upgrade,apt install,apt remove,apt autoremove, anddpkg -L/dpkg -Sto query. - Repositories live in deb822
.sourcesfiles in/etc/apt/sources.list.d/, with keys in their own keyring files referenced bySigned-By.apt-keyis gone. - On Fedora and RHEL:
dnf install,dnf upgrade,dnf remove,rpm -qf/rpm -ql, and.repofiles in/etc/yum.repos.d/. - Snap, Flatpak and AppImage bundle dependencies and suit desktop apps; servers are easier to patch with distribution packages.
- Use virtual environments for Python libraries instead of the system
pip.
Next: User and Group Management, where you create accounts, manage groups and set up sudo and SSH keys.
Keep Learning
- Interview questions: Linux package management
- Introduction to Docker, which starts from the Docker repository you added above
- Linux Command Line Quiz
Tags
Found an issue?