APT Guide (Debian/Ubuntu)

APT Guide (Debian/Ubuntu)

APT is the layer between you and the 60,000+ packages in the Debian and Ubuntu repositories. It handles dependency resolution, signature verification, and the actual installation work. Most users know three commands. This guide covers the full toolkit, from everyday usage through repository configuration, version pinning, and the dpkg layer underneath.

The two-step model: update then upgrade

The most important thing to understand about APT is that syncing the package index and upgrading packages are two separate operations.

# Step 1: refresh the local index from all repos
sudo apt update

# Step 2: upgrade installed packages to their latest versions
sudo apt upgrade

apt update downloads the current package lists from every repository in your sources configuration. It does not install or change anything. apt upgrade then compares your installed packages against the updated index and installs newer versions where available.

Always run apt update before apt upgrade. Without it, upgrade works from a stale index and may not find the latest versions.

Installing and removing packages

# Install a package
sudo apt install nginx

# Install multiple packages at once
sudo apt install nginx postgresql-16 redis-server certbot

# Install a specific version
sudo apt install nginx=1.24.0-1

# Reinstall a package (useful if files were accidentally deleted)
sudo apt install --reinstall nginx

# Remove a package but keep its configuration files
sudo apt remove nginx

# Remove a package and its configuration files
sudo apt purge nginx

# Remove packages that were auto-installed as dependencies
# and are no longer needed by anything
sudo apt autoremove

# Remove + purge in one step
sudo apt purge nginx && sudo apt autoremove

The difference between remove and purge matters when you plan to reinstall. remove leaves config files in place so reinstalling picks up where you left off. purge wipes the config, giving you a clean slate.

Searching and inspecting packages

# Search by name or description
apt search nginx
apt search "web server"

# Show full metadata for a package
apt show nginx

# Show all available versions across repos
apt-cache policy nginx

# List files that would be installed by a package
# (before installing)
apt-file list nginx          # requires: sudo apt install apt-file && sudo apt-file update

# Show reverse dependencies (what depends on this package)
apt-cache rdepends nginx

# Show forward dependencies (what this package needs)
apt-cache depends nginx

# List all installed packages
apt list --installed

# List packages with available upgrades
apt list --upgradable

# Check if a specific package is installed
dpkg -l nginx
apt list --installed 2>/dev/null | grep nginx

full-upgrade vs upgrade

apt upgrade is safe for routine updates: it never removes a package to satisfy new dependencies. apt full-upgrade (equivalent to the older apt-get dist-upgrade) will remove packages when necessary.

# Safe upgrade: no removals
sudo apt upgrade

# Full upgrade: resolves complex dependency changes, may remove packages
sudo apt full-upgrade

# See what would change before committing
apt upgrade --dry-run
apt full-upgrade --dry-run

Use full-upgrade when upgrade reports packages being held back. The held-back packages are usually being held because their new version requires removing or replacing something, which upgrade refuses to do without explicit permission.

Holding packages

Sometimes you need to freeze a package at its current version, for example to keep a working kernel or avoid a known-bad release.

# Hold a package at its current version
sudo apt-mark hold nginx

# Release the hold
sudo apt-mark unhold nginx

# See all held packages
apt-mark showhold

# Alternative with dpkg
echo "nginx hold" | sudo dpkg --set-selections
dpkg --get-selections | grep hold

Held packages are skipped during apt upgrade and apt full-upgrade. They appear in the “The following packages have been kept back” section of upgrade output.

apt-get vs apt

apt is the recommended command for interactive use. apt-get is the older command with a stable output format, preferred in scripts.

# Interactive use: apt (coloured output, progress bar)
sudo apt install nginx

# Scripts and automation: apt-get (stable output, no colour by default)
sudo apt-get install -y nginx
sudo apt-get update && sudo apt-get upgrade -y

# apt-get equivalents for all common commands
sudo apt-get install packagename
sudo apt-get remove packagename
sudo apt-get purge packagename
sudo apt-get autoremove
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade     # equivalent to apt full-upgrade

The -y flag skips confirmation prompts, useful in scripts and provisioning.

Repository configuration

Repositories are configured in /etc/apt/sources.list and individual files under /etc/apt/sources.list.d/. The modern format uses .sources files; the traditional format uses .list files. Both work.

# View your current repo configuration
cat /etc/apt/sources.list
ls /etc/apt/sources.list.d/

# A typical Ubuntu sources.list entry (traditional format)
# deb https://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
# deb https://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
# deb https://security.ubuntu.com/ubuntu noble-security main restricted universe multiverse

# Modern .sources format (one-line-per-entry replaced by stanza blocks)
# Types: deb
# URIs: https://archive.ubuntu.com/ubuntu
# Suites: noble noble-updates
# Components: main restricted universe multiverse
# Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

The components control which categories of packages are available:

  • main: officially supported free software
  • restricted: officially supported, may have proprietary components (drivers)
  • universe: community-maintained free software
  • multiverse: not free or with restricted distribution

On Debian:

  • main: DFSG-compliant free software
  • contrib: free software depending on non-free packages
  • non-free: proprietary or non-free software
  • non-free-firmware: firmware blobs, split from non-free in Debian 12

Adding third-party repositories securely

The current best practice stores repository signing keys separately from the apt trusted keychain, in /usr/share/keyrings/ or /etc/apt/keyrings/. Each .sources or .list entry then references its key with signed-by=.

# Pattern for adding a third-party repo (e.g. Docker on Ubuntu)

# 1. Create the keyrings directory if it does not exist
sudo install -d -m 0755 /etc/apt/keyrings

# 2. Download and store the signing key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# 3. Add the repository source, referencing the key
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list

# 4. Update and install
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io

Avoid apt-key add and the trusted.gpg keychain for new repos. Those approaches trust the key for all repositories, not just the one you intended.

Backports

Backports repositories provide newer versions of selected packages for the current stable release, compiled to run on the stable base system. Useful when you need a newer version of a specific application without upgrading the entire OS.

# Enable Debian backports (replace bookworm with your release)
echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free" | \
  sudo tee /etc/apt/sources.list.d/backports.list
sudo apt update

# Install a package from backports explicitly
sudo apt install -t bookworm-backports git

# On Ubuntu, backports are already enabled in most installs
sudo apt install -t noble-backports some-package

Backports packages do not install automatically during apt upgrade. You must request them explicitly with -t release-backports.

APT pinning

Pinning lets you control which repository version of a package APT prefers, or to lock a package to a specific release. Configuration goes in /etc/apt/preferences or files under /etc/apt/preferences.d/.

# View current pinning
apt-cache policy

# Pin a package to prefer a specific release
# File: /etc/apt/preferences.d/nginx
# Package: nginx
# Pin: release a=noble-backports
# Pin-Priority: 900

# Pin priorities:
# 1001: always install this version even if it means downgrading
# 990:  prefer this version but do not downgrade
# 500:  default (same priority as the matching release)
# 100:  install only if no other version is available
# -1:   never install this package

# Block a package from ever being installed
# Package: package-to-block
# Pin: release *
# Pin-Priority: -1

Pinning is powerful but can be confusing. Prefer apt-mark hold for simple version freezes and reserve pinning for multi-repo configurations where you want packages from different sources.

The dpkg layer

dpkg is the low-level tool that APT uses internally. You need it directly for inspecting or installing individual .deb files, fixing broken states, and querying the package database.

# Install a local .deb file
sudo dpkg -i package.deb

# Remove a package
sudo dpkg -r packagename

# Purge a package
sudo dpkg -P packagename

# List all installed packages
dpkg -l

# Check if a package is installed and its version
dpkg -l nginx

# List files installed by a package
dpkg -L nginx

# Find which package owns a file
dpkg -S /usr/sbin/nginx

# Check package status
dpkg -s nginx

# Fix packages stuck in half-configured state
sudo dpkg --configure -a

# Fix broken dependencies after a failed install
sudo apt install -f

When apt install or apt upgrade fails partway through, it often leaves packages in an inconsistent state. The recovery sequence is:

sudo dpkg --configure -a        # configure anything unpacked but not configured
sudo apt install -f             # fix broken dependencies
sudo apt upgrade                # retry

Clearing the cache

APT caches downloaded packages in /var/cache/apt/archives/. On a busy system or after many upgrades this can accumulate gigabytes.

# See how much space the cache is using
du -sh /var/cache/apt/archives/

# Remove packages that can no longer be downloaded (not in any repo)
sudo apt autoclean

# Remove all cached packages
sudo apt clean

# Remove the package lists (re-downloaded on next apt update)
sudo rm -rf /var/lib/apt/lists/*
sudo apt update

autoclean is safe to run regularly. clean frees more space but means any reinstall requires re-downloading.

Unattended upgrades

For servers, unattended-upgrades installs security updates automatically without administrator intervention:

# Install
sudo apt install unattended-upgrades

# Configure
sudo dpkg-reconfigure unattended-upgrades

# Configuration file
cat /etc/apt/apt.conf.d/50unattended-upgrades

# Check what it would do (dry run)
sudo unattended-upgrade --dry-run --debug

# View the log
cat /var/log/unattended-upgrades/unattended-upgrades.log

By default, unattended-upgrades only applies security updates from ${distro_codename}-security. Extending it to all updates is possible but risks breaking changes; most administrators leave it on security-only.

Quick reference

# Daily workflow
sudo apt update && sudo apt upgrade

# Install / remove
sudo apt install pkg
sudo apt purge pkg && sudo apt autoremove

# Search and inspect
apt search term
apt show pkg
apt-cache policy pkg

# Version management
sudo apt install pkg=version
sudo apt-mark hold pkg
sudo apt-mark unhold pkg
apt-mark showhold

# Repository management
sudo apt update                    # refresh index
sudo add-apt-repository ppa:name   # Ubuntu PPAs
sudo apt edit-sources              # open sources safely in $EDITOR

# Maintenance
sudo apt autoremove
sudo apt clean
sudo dpkg --configure -a
sudo apt install -f

APT rewards the time spent learning it. Once the mental model of index versus install is clear, and you know the difference between upgrade, full-upgrade, and hold, day-to-day package management becomes fast and predictable.

Frequently Asked Questions

What is APT in Linux?

APT (Advanced Package Tool) is the package management system used by Debian, Ubuntu, Linux Mint, and their derivatives. It handles downloading, installing, upgrading, and removing software packages from configured repositories. APT resolves dependencies automatically, verifies package signatures, and keeps a record of what is installed. The main user-facing commands are apt, apt-get, and apt-cache.

What is the difference between apt update and apt upgrade?

apt update refreshes the local package index by downloading the latest list of available packages from all configured repositories. It does not install or upgrade anything. apt upgrade then installs the newest available version of every package that is already installed, as long as doing so does not require removing any existing packages. You should always run apt update before apt upgrade to ensure you are working from the latest package list.

What is the difference between apt upgrade and apt full-upgrade?

apt upgrade upgrades installed packages but will not remove any existing packages to satisfy new dependencies. apt full-upgrade (equivalent to apt-get dist-upgrade) will also remove packages when necessary to resolve dependency changes. full-upgrade is needed when a major upgrade changes which packages depend on what, such as a kernel update that replaces an older kernel package.

How do I install a specific version of a package with apt?

Use apt install packagename=version to install a specific version. For example: sudo apt install nginx=1.24.0-1 installs that exact version. You can find available versions with apt-cache policy packagename, which shows all versions available across your configured repositories and which one is currently installed.

How do I prevent a package from being upgraded with apt?

Use apt-mark hold packagename to prevent a package from being upgraded. The package will remain at its current version during apt upgrade and apt full-upgrade. To release the hold and allow upgrades again, use apt-mark unhold packagename. To see all held packages, run apt-mark showhold.