apt vs yum vs dnf — Linux Package Managers Demystified
You just got a new job. Half the servers run Ubuntu, the other half run CentOS. Your Ansible playbooks need to work on both. Your Dockerfiles target different base images. Which package manager do you use? What are the actual differences? Let's clear this up once and for all.
The Two Families of Linux Packaging
Linux distributions fall into two major packaging families:
| Family | Package Format | Low-Level Tool | High-Level Tool | Distros |
|---|---|---|---|---|
| Debian | .deb | dpkg | apt / apt-get | Debian, Ubuntu, Mint |
| Red Hat | .rpm | rpm | yum / dnf | RHEL, CentOS, Fedora, Rocky, Alma |
The low-level tools (dpkg, rpm) handle individual package files. The high-level tools (apt, yum, dnf) handle dependency resolution, repositories, and updates.
apt — The Debian/Ubuntu Way
apt is the modern, user-friendly replacement for apt-get. Use apt for interactive use, apt-get in scripts (it has a more stable output format).
# Update package index (always do this first!)
sudo apt update
# Upgrade all installed packages
sudo apt upgrade -y
# Full upgrade (handles dependency changes)
sudo apt full-upgrade -y
# Install a package
sudo apt install nginx curl vim -y
# Remove a package (keeps config files)
sudo apt remove nginx
# Remove package AND config files
sudo apt purge nginx
# Remove unused dependencies
sudo apt autoremove -y
# Search for a package
apt search "web server"
apt list --installed | grep nginx
# Show package details
apt show nginx
Managing Repositories
# List current repositories
cat /etc/apt/sources.list
ls /etc/apt/sources.list.d/
# Add a third-party repository (example: Docker)
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce -y
Package Pinning — Hold a Version
Sometimes you don't want a package to auto-upgrade (looking at you, kernel updates on production servers).
# Hold a package at its current version
sudo apt-mark hold nginx
# nginx set on hold.
# List held packages
apt-mark showhold
# Release the hold
sudo apt-mark unhold nginx
# Install a specific version
apt list -a nginx # See available versions
sudo apt install nginx=1.24.0-1ubuntu1 # Install exact version
yum — The Classic Red Hat Way
yum (Yellowdog Updater Modified) was the default for RHEL/CentOS for years. It works but it's slow because it's written in Python and resolves dependencies sequentially.
# Update package index and upgrade everything
sudo yum update -y
# Install packages
sudo yum install nginx curl vim -y
# Remove a package
sudo yum remove nginx -y
# Search for a package
yum search "web server"
yum list installed | grep nginx
# Show package info
yum info nginx
# List available updates
yum check-update
# Clean cached data
sudo yum clean all
# View history and rollback
yum history list
sudo yum history undo 15 # Undo transaction 15
dnf — The Modern Red Hat Way
dnf (Dandified Yum) is yum's successor. It's faster, has better dependency resolution, and is now the default on Fedora, RHEL 8+, CentOS Stream, Rocky Linux, and AlmaLinux.
# dnf commands mirror yum — easy transition
sudo dnf update -y
sudo dnf install nginx -y
sudo dnf remove nginx -y
sudo dnf search "web server"
dnf info nginx
dnf list installed
# dnf-exclusive features:
# Module streams (multiple versions of the same software)
dnf module list nodejs
sudo dnf module enable nodejs:18
sudo dnf module install nodejs:18
# Automatic updates
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer
Managing Repositories (yum/dnf)
# List enabled repositories
dnf repolist
dnf repolist all # Including disabled
# Add EPEL repository (Extra Packages for Enterprise Linux)
sudo dnf install epel-release -y
# Add a custom repo
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
# Disable a repo temporarily
sudo dnf install somepackage --disablerepo=epel
# Enable a disabled repo temporarily
sudo dnf install somepackage --enablerepo=testing
Version Locking with dnf
# Install the versionlock plugin
sudo dnf install python3-dnf-plugin-versionlock
# Lock a package version
sudo dnf versionlock add nginx
# List locked packages
dnf versionlock list
# Remove a lock
sudo dnf versionlock delete nginx
# Clear all locks
sudo dnf versionlock clear
Head-to-Head Comparison
Here's the same task in all three package managers:
| Task | apt (Debian/Ubuntu) | yum (RHEL 7/CentOS 7) | dnf (RHEL 8+/Fedora) |
|---|---|---|---|
| Update index | apt update | yum check-update | dnf check-update |
| Upgrade all | apt upgrade -y | yum update -y | dnf upgrade -y |
| Install | apt install pkg -y | yum install pkg -y | dnf install pkg -y |
| Remove | apt remove pkg | yum remove pkg | dnf remove pkg |
| Search | apt search term | yum search term | dnf search term |
| Info | apt show pkg | yum info pkg | dnf info pkg |
| List installed | apt list --installed | yum list installed | dnf list installed |
| Clean cache | apt clean | yum clean all | dnf clean all |
| History/rollback | N/A (use snapshots) | yum history undo N | dnf history undo N |
| Lock version | apt-mark hold pkg | yum versionlock pkg | dnf versionlock add pkg |
Low-Level Tools — dpkg and rpm
Sometimes you need to work with individual package files directly.
# Debian: dpkg
dpkg -i package.deb # Install a .deb file
dpkg -r package # Remove package
dpkg -l | grep nginx # List installed, filter
dpkg -L nginx # List files installed by package
dpkg -S /usr/sbin/nginx # Which package owns this file?
# Red Hat: rpm
rpm -ivh package.rpm # Install a .rpm file
rpm -e package # Remove package
rpm -qa | grep nginx # List installed, filter
rpm -ql nginx # List files installed by package
rpm -qf /usr/sbin/nginx # Which package owns this file?
Writing Cross-Distro Scripts
In real DevOps work, your scripts need to handle both families. Here's a practical pattern:
#!/bin/bash
# install-tools.sh — Works on Debian and Red Hat families
install_packages() {
if command -v apt &> /dev/null; then
echo "Detected Debian-based system"
sudo apt update
sudo apt install -y curl wget vim htop jq
elif command -v dnf &> /dev/null; then
echo "Detected RHEL 8+ / Fedora"
sudo dnf install -y curl wget vim htop jq
elif command -v yum &> /dev/null; then
echo "Detected RHEL 7 / CentOS 7"
sudo yum install -y curl wget vim htop jq
else
echo "Unsupported package manager" >&2
exit 1
fi
}
install_packages
Dockerfile Best Practices
# Debian/Ubuntu base — clean up apt cache to reduce image size
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
nginx \
&& rm -rf /var/lib/apt/lists/*
# RHEL/Fedora base — clean up dnf cache
FROM fedora:39
RUN dnf install -y \
curl \
nginx \
&& dnf clean all \
&& rm -rf /var/cache/dnf
Key Dockerfile tips:
- Always combine
updateandinstallin oneRUNlayer - Use
--no-install-recommends(apt) to skip optional dependencies - Clean the cache in the same
RUNto keep the layer small - Pin versions in production images:
nginx=1.24.0-1ubuntu1
When to Use Which?
- Ubuntu/Debian is dominant in containers, cloud VMs, and developer machines. Use
apt. - RHEL/Rocky/Alma is dominant in enterprise, banking, and compliance-heavy environments. Use
dnf. - CentOS 7 still exists in legacy environments. Use
yum, but plan your migration. - Fedora is great for testing what's coming to RHEL. Use
dnf.
The commands are similar enough that switching between them is painless. The biggest adjustment is remembering that apt needs update before install, while dnf handles it automatically.
Next up: Linux Users & Groups — a new developer joins your team. Here's how to set up their Linux access properly.
