apt is the high-level interface to the Debian package system.
dpkg is the low-level tool. Most production work uses apt;
dpkg is for queries and the rare case where apt fails.
The day-to-day commands
Configuration changeapt update + upgrade— apt update refreshes the package index from the configured repositories. apt upgrade upgrades every installed package that has a newer version WITHOUT removing anything. The last line is the one that matters: N not upgraded means N updates were skipped because they needed a removal, and those are kept back until you run full-upgrade. Run on a single host before rolling out to the fleet.
$ sudo apt update; sudo apt upgrade
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease\n...\nReading package lists... Done\nBuilding dependency tree... Done\n...\n0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Illustrative output
upgrade never removes; full-upgrade may
apt upgrade will not remove an installed package. When an
upgrade cannot complete without a removal, apt skips it and
reports it as kept back:
The following packages have been kept back: linux-generic linux-headers-generic linux-image-generic0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
apt full-upgrade does the same job but is permitted to remove
packages to upgrade the system as a whole. It is the same
operation as the older apt-get dist-upgrade.
Command
Removes packages?
The risk it carries
apt upgrade
Never
Silently skips updates, including security fixes
apt full-upgrade
Yes, when needed
May remove a package you needed, unattended
Read-only / Safeapt search / show— apt search <pattern> finds packages by name or description. apt show <package> shows the package's metadata: version, dependencies, size, description, maintainer. Use show before installing to confirm the package is what you expect.
Configuration changeinstall / remove / purge— apt install adds the package and its dependencies. apt remove removes the package but keeps its configuration files (conffiles). apt purge removes the package and its conffiles. Production: prefer remove for rollback safety; purge when you want a complete uninstall.
Read-only / Safedpkg queries— dpkg -l PATTERN lists installed packages matching the pattern. dpkg -L PACKAGE lists files installed by the package. dpkg -S PATH identifies which package owns the file. Three queries cover 90% of production needs.
Read-only / Safeinstalled count / holds— apt list --installed | wc -l counts installed packages. apt-mark showhold lists packages under an EXPLICIT hold, which is a deliberate operator decision — it is not the same thing as the kept back list from apt upgrade, which is a dependency outcome. Check showhold first when a package will not upgrade: if it is empty, the cause is a needed removal and full-upgrade is the answer.
$ apt list --installed 2>/dev/null | wc -l; apt-mark showhold
...
Illustrative output
Reading apt logs
Read-only / Safeapt history— /var/log/apt/history.log records every apt invocation with the command line, the packages installed/removed/upgraded, and the timestamp. Use this for post-incident review: 'who upgraded openssh-server on Aug 9?'
Read-only / Safeapt term log— /var/log/apt/term.log captures the full output of every apt run, including the dpkg post-install scripts. /var/log/apt/eipp.log.x.gz are rotated logs. The list of files in /var/log/apt/ tells you how far back the apt history is preserved.
$ tail -50 /var/log/apt/term.log; ls -l /var/log/apt/
...
Illustrative output
Configuring repositories
Read-only / Safesources.list— On Ubuntu 24.04 and later /etc/apt/sources.list is a stub comment. The real repository definitions live in /etc/apt/sources.list.d/ as deb822 .sources files. Reading sources.list alone, or globbing *.list, reports no repositories on a current host.
$ cat /etc/apt/sources.list; ls /etc/apt/sources.list.d/
# Ubuntu sources have moved to /etc/apt/sources.list.d/ubuntu.sources
docker.sources ubuntu.sources
Illustrative output
The deb822 .sources format
Debian 12 and Ubuntu 24.04 ship the archive as a deb822 stanza,
not as one-line deb entries. One key field is new and matters:
Signed-By names the only key permitted to sign this
repository, instead of accepting any key in the global trust
store.
Read-only / Safeubuntu.sources— Suites replaces the per-line release names, so one stanza covers noble, noble-updates and noble-backports. Components are the same four archives: main is the primary supported archive; restricted is non-free drivers; universe is community-maintained; multiverse is non-free with patent restrictions. The one-line equivalent of the first stanza is: deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu/ noble main restricted universe multiverse.
$ cat /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
Types: deb
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Illustrative output
The one-line format still works and older hosts still use it, so
any inventory must read both:
Configuration changeadd-apt-repository— add-apt-repository adds a line to /etc/apt/sources.list.d/ and downloads the repository's signing key to /etc/apt/trusted.gpg.d/. For production, prefer downloading the key manually and verifying its fingerprint against the vendor's published fingerprint before trusting it.