Cheat Sheets

APT Cheat Sheet: apt and apt-get Commands for Ubuntu/Debian

This apt cheat sheet sorts the commands you’ll actually type on Debian and Ubuntu by task. It covers install, remove, update, search, hold and fix-broken, then settles the apt vs apt-get question. Tables come first for copying, and the sections below show what each command prints, including the dependency errors that send people searching.

Original content from computingforgeeks.com - post 185403

Commands new in apt 3.1, such as history-undo and apt why, are flagged, and a release table at the end shows which apt your distro ships. Every command and output below was built and run on Ubuntu 26.04.1 LTS with apt 3.2.1 in November 2026, so the output matches the newer apt 3 layout.

APT Cheat Sheet (Quick Reference)

Commands that change the system need sudo and read-only queries do not. On apt 3 the query commands also open in a pager when you run them in a terminal, so press q to get your prompt back.

Update and upgrade

CommandWhat it does
sudo apt updateRefresh the package index from every configured source
apt list --upgradableShow packages with a newer candidate version
sudo apt upgradeUpgrade installed packages, never removing any
sudo apt full-upgradeUpgrade and allow removals to resolve conflicts
sudo apt install --only-upgrade nginxUpgrade one package if it’s installed, never install it fresh
sudo apt -o APT::Get::Always-Include-Phased-Updates=true upgradeTake Ubuntu phased updates now instead of waiting
apt full-upgrade -sSimulate the upgrade and change nothing

Install packages

CommandWhat it does
sudo apt install nginxInstall a package plus its dependencies and recommends
sudo apt install -y jqInstall without the confirmation prompt
sudo apt install nginx=1.28.3-2ubuntu1 nginx-common=1.28.3-2ubuntu1Install an exact version, pinning strict siblings on the same line
sudo apt install ./package.debInstall a local .deb and pull its dependencies from the repos
sudo apt install --no-install-recommends fortune-modSkip Recommends, install hard dependencies only
sudo apt reinstall treeReinstall the current version over itself
apt download figletDownload the .deb into the current directory, no install

Remove and clean up

CommandWhat it does
sudo apt remove nginxRemove the package, keep its config files in /etc
sudo apt purge nginxRemove the package and its config files
sudo apt autoremoveRemove dependencies nothing needs any more
sudo apt autoremove --purgeSame, and delete their config files too
sudo apt purge '~c'Purge every removed package that left config behind (rc state)
sudo apt cleanEmpty the downloaded .deb cache in /var/cache/apt/archives
sudo apt autocleanDelete only cached .debs that can no longer be downloaded

Search and inspect

CommandWhat it does
apt search --names-only '^nginx'Search package names only, regex allowed
apt show nginxVersion, size, dependencies and description
apt show -a nginxShow every available version, not just the candidate
apt policy nginxInstalled and candidate version, with the repo and priority of each
apt-cache madison nginxOne line per available version and source
apt list --installedEvery installed package with version and state
apt depends nginxWhat a package depends on
apt rdepends --installed libonig5Which installed packages depend on this one

Hold and mark packages

CommandWhat it does
sudo apt-mark hold nginx nginx-commonFreeze packages at their current version
apt-mark showholdList held packages
sudo apt-mark unhold nginx nginx-commonRelease the hold
apt-mark showmanualPackages you installed by name
apt-mark showautoPackages pulled in as dependencies (autoremove candidates)
sudo apt-mark manual figletMark a package manual so autoremove never takes it

Fix broken installs

CommandWhat it does
sudo apt --fix-broken installInstall missing dependencies for half-installed packages
sudo dpkg --configure -aFinish configuring packages left unpacked by an interrupted run
sudo dpkg --auditList packages that are unpacked but not configured
sudo apt-get checkCheck the dependency tree for unmet dependencies
sudo apt-get -o DPkg::Lock::Timeout=60 install treeWait up to 60 s for the dpkg lock instead of failing

History and why (apt 3.1+)

CommandWhat it does
sudo apt history-listNumbered list of past apt transactions
sudo apt history-info 7Every package one transaction changed
sudo apt history-undo 7Reverse one transaction
apt why libonig5Trace which package pulled a dependency in
apt why-not apache2Explain a solver decision (never-requested packages show “undecided”)
zgrep -h Commandline /var/log/apt/history.log*Past apt command lines on apt 2.x releases

dpkg queries

CommandWhat it does
dpkg -l nginxInstall state of a package (ii, rc, iU, un)
dpkg -L curlFiles a package installed
dpkg -S /usr/bin/curlWhich package owns a file
sudo dpkg -i package.debInstall a local .deb with no dependency resolution

The rest of the page walks through the same commands in task order, with the output each one gave on the lab box and the fix for the errors that came up along the way.

Update the Index and Upgrade Packages

apt update only downloads package lists and does not change a single installed file. Run it before any install or upgrade, because apt resolves versions against whatever index it last fetched. A stale index makes apt ask the mirror for .deb files that have already rotated out, so the install fails with a 404 halfway through.

sudo apt update

The last line tells you whether anything is waiting. Here four indexes were already current and two packages had updates:

Hit:1 http://archive.ubuntu.com/ubuntu resolute InRelease
Hit:2 http://archive.ubuntu.com/ubuntu resolute-updates InRelease
Hit:3 http://archive.ubuntu.com/ubuntu resolute-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu resolute-security InRelease
2 packages can be upgraded. Run 'apt list --upgradable' to see them.

List them before you upgrade so you know what’s about to move. A kernel, glibc or database server in this list deserves a maintenance window, because those need a reboot or a service restart to take effect. A couple of Python helpers don’t, so you can patch them during the day. Each line shows the repo the new version comes from, the new version and the one you’re on.

apt list --upgradable

Both packages here come from resolute-updates, the regular bug-fix pocket.

python3-software-properties/resolute-updates 0.120.1 all [upgradable from: 0.120]
software-properties-common/resolute-updates 0.120.1 all [upgradable from: 0.120]

Both steps together, as they ran on the lab VM:

sudo apt update refreshing four Ubuntu 26.04 indexes and apt list --upgradable showing two packages

Now upgrade. apt upgrade never removes a package, which makes it the safe default for routine patching. If an update would need a removal, apt keeps that package back and tells you instead of guessing.

sudo apt upgrade -y

On Ubuntu this often upgrades nothing, and that is not a bug. The two packages from the list above were held back by phasing.

The following package was automatically installed and is no longer required:
  pollinate
Use 'sudo apt autoremove' to remove it.

Not upgrading yet due to phasing:
  python3-software-properties  software-properties-common

Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 2

Phased updates go out to a growing percentage of Ubuntu machines over a few days, so a bad build hits a small slice first and gets pulled before it reaches everyone. Your box will get them on its own, and Ubuntu’s phased updates page explains how the rollout percentage is picked. Override it only when you have a reason, such as a security fix you’re tracking or two servers that must run the same build. The override applies to one run.

sudo apt -o APT::Get::Always-Include-Phased-Updates=true upgrade -y

The same two packages now move.

Upgrading:
  python3-software-properties  software-properties-common

Summary:
  Upgrading: 2, Installing: 0, Removing: 0, Not Upgrading: 0
  Download size: 45.3 kB
  Space needed: 0 B / 16.9 GB available

Use sudo apt full-upgrade when an upgrade needs to remove or replace packages, which is what new kernel series and library transitions do. Run it with -s first. The simulation prints the same plan and touches nothing, so you see any removal before it happens. If apt itself is behind on a security fix, patch it before anything else, and the APT CVE-2026-109518 guide covers checking the installed apt build.

Install Packages, Versions and Local .deb Files

A plain sudo apt install nginx installs the candidate version, its dependencies and its Recommends. Before pinning a version, ask apt which ones exist, because the version string has to match exactly, Debian revision and Ubuntu suffix included. The upstream release number alone (1.28.3) is not a valid version string here.

apt policy nginx

The release pocket carries the original build and resolute-updates carries the patched one, which is the candidate.

nginx:
  Installed: (none)
  Candidate: 1.28.3-2ubuntu1.12
  Version table:
     1.28.3-2ubuntu1.12 500
        500 http://archive.ubuntu.com/ubuntu resolute-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu resolute-security/main amd64 Packages
     1.28.3-2ubuntu1 500
        500 http://archive.ubuntu.com/ubuntu resolute/main amd64 Packages

Asking for the older build with nginx=1.28.3-2ubuntu1 on its own fails. nginx depends on nginx-common of the exact same version, and apt won’t pick an older sibling you didn’t name, so the solver reports two conflicting assignments and stops. Check the Depends: line of apt show for any (= version) entry before you pin, since that is the list of siblings you’ll have to name too.

apt policy nginx version table and apt install nginx=1.28.3-2ubuntu1 failing on nginx-common unsatisfied dependency

Pin every package that carries an (= version) dependency on the same line.

sudo apt install -y nginx=1.28.3-2ubuntu1 nginx-common=1.28.3-2ubuntu1

apt now resolves both and shows the plan before it downloads anything.

Installing:
  nginx  nginx-common

Suggested packages:
  fcgiwrap  nginx-doc  ssl-cert

Summary:
  Upgrading: 0, Installing: 2, Removing: 0, Not Upgrading: 2
  Download size: 652 kB
  Space needed: 1853 kB / 16.5 GB available

Pinning a version doesn’t keep it there. The next apt upgrade moves it straight back to the candidate unless you hold it, which is the next section. Naming nginx-common also marked it manually installed, so a later autoremove won’t clean it up for you.

For local .deb files, prefer sudo apt install ./package.deb over dpkg -i. A path with a slash in it tells apt the argument is a file, and apt then fetches the dependencies from your repos. With fortune-mod, the apt route installed three packages while the dpkg route broke, which the fix-broken section reproduces. Add --no-install-recommends when you want a lean server, because Recommends often drag in docs and helpers you never use. A simulation of the same fortune-mod install dropped from 3 packages to 2 with the flag.

Keep a Package Back with apt-mark hold

A hold stops apt upgrade and full-upgrade from touching a package. It’s the right tool for a pinned database, a Kubernetes node’s kubelet, or the nginx build you just tested, because the next routine upgrade would otherwise undo your pin without asking. The workflow is short.

  1. Hold the package and every sibling with a strict version dependency.
  2. Confirm the hold with apt-mark showhold.
  3. Upgrade as normal and check that the held packages land under “Not upgrading”.

Hold both nginx packages. Holding nginx alone means nginx-common gets kept back too, because upgrading it would break nginx’s strict version dependency, and an explicit apt install nginx-common would then fail with the same error you hit when pinning.

sudo apt-mark hold nginx nginx-common
apt-mark showhold

An upgrade afterwards keeps them back and lists them in their own “Not upgrading” block, separate from the phased packages. The summary count of 4 is the two held plus the two phased ones.

apt-mark hold on nginx and nginx-common, then apt upgrade listing them under Not upgrading plus two phased packages

A hold stays in force during a release upgrade too, so list holds before you start one. The Debian 12 to 13 upgrade guide checks for them in its pre-flight. When you’re ready to move, release the hold:

sudo apt-mark unhold nginx nginx-common

apt confirms each one:

Canceled hold on nginx.
Canceled hold on nginx-common.

To bring just those two up to date without running a full system upgrade, use sudo apt install --only-upgrade nginx nginx-common. It upgrades installed packages only and refuses to install a package you don’t already have, which makes it safe in scripts that loop over a host list. The single package upgrade guide covers the edge cases.

Remove vs Purge and Clean the Cache

remove deletes the program and keeps its configuration, so a reinstall picks up your old settings. purge deletes both, which is what you want when the config itself is the problem. On the lab box, apt remove nginx left nginx-common installed and /etc/nginx in place, because nginx-common had been named on the install line and was marked manual. Purging nginx-common removed the directory.

dpkg -l after apt remove nginx with /etc/nginx still present, then gone after apt purge nginx-common

Purge prints an asterisk after each package name in its plan, which is the quickest way to tell the two apart before you confirm.

sudo apt purge -y nginx-common

Look for the * and the “Purging configuration files” line.

REMOVING:
  nginx-common*

Summary:
  Upgrading: 0, Installing: 0, Removing: 1, Not Upgrading: 2
  Freed space: 232 kB

Removing nginx-common (1.28.3-2ubuntu1.12) ...
Purging configuration files for nginx-common (1.28.3-2ubuntu1.12) ...

Plain autoremove has the same gap as remove. On the lab VM it removed the unused pollinate package but left its config behind, so dpkg -l still listed it in the rc state, meaning removed with config remaining. Those entries pile up for years on long-lived servers and make dpkg -l output harder to read. The ~c pattern matches every package in that state, so one purge clears them all:

sudo apt purge '~c'

The download cache is the other thing that grows, though not from apt itself: apt deletes each .deb after a successful install unless APT::Keep-Downloaded-Packages is set to true. apt-get and unattended-upgrades keep theirs. After the cloud image’s apt-get dist-upgrade, /var/cache/apt/archives held 232 .deb files and 383 MB, and sudo apt clean took it down to 28 KB. That matters on small VMs and container images, where a forgotten cache can be the difference between a full root disk and a healthy one. For a full cleanup after removing software, run these in order:

  1. Purge the package you no longer want with sudo apt purge nginx.
  2. Drop its orphaned dependencies and their config with sudo apt autoremove --purge.
  3. Clear any older rc leftovers with sudo apt purge '~c'.
  4. Empty the download cache with sudo apt clean, or use sudo apt autoclean to keep .debs that are still current.

Step 4 is safe to run any time, since apt simply downloads a package again the next time it needs one.

Fix Broken Packages and Unmet Dependencies

The classic way to break apt is installing a downloaded .deb with dpkg -i. dpkg unpacks the file but has no idea where to get dependencies, so it leaves the package unconfigured and every later apt command refuses to run. Vendor downloads (browsers, VPN clients, chat apps) are where most people hit this. These two commands reproduce it with a small package from the Ubuntu archive. They break apt on purpose, so run them on a test VM, not a server you care about.

cd /tmp && apt download fortune-mod
sudo dpkg -i /tmp/fortune-mod_*.deb

dpkg stops on the missing librecode3. Worse, the next unrelated install fails too, because apt refuses to plan anything while one package sits half-installed, and it says so with “Unmet dependencies”.

dpkg -i leaving fortune-mod unconfigured on a missing librecode3 and apt install refusing with Unmet dependencies

Run the fix apt suggests, with no package names. It installs whatever the half-installed package needs and finishes configuring it. Adding a package name here makes apt try to solve both jobs at once, which is rarely what you want while the system is broken.

sudo apt --fix-broken install -y

“Correcting dependencies… Done” and the “Setting up fortune-mod” line mean the system is consistent again.

sudo apt --fix-broken install pulling librecode3 and finishing the half-configured fortune-mod package

There’s a catch the summary hides. --fix-broken installed only the hard dependency, librecode3, and skipped the Recommends. Running fortune afterwards printed “No fortunes found” because the data package, fortunes-min, never came along. When apt install ./fortune-mod...deb was used instead, apt pulled all three packages and the command worked first time. That’s the practical reason to stop using dpkg -i for anything with dependencies.

A different message, “dpkg was interrupted”, means a run died between unpacking and configuring, usually because an SSH session dropped or the OOM killer hit dpkg. Nothing is missing from the repos in that case, so --fix-broken is the wrong first move. Ask dpkg what it left behind instead. On the lab box a package unpacked with dpkg --unpack showed up in the iU state.

sudo dpkg --audit

The audit names each package that still needs configuring:

The following packages have been unpacked but not yet configured.
They must be configured using dpkg --configure or the configure
menu option in dselect for them to work:
 figlet               Make large character ASCII banners out of ordinary text

Finish the job for every stuck package at once.

sudo dpkg --configure -a

The package moves from iU to ii, fully installed.

Setting up figlet (2.2.5-3.1) ...
update-alternatives: using /usr/bin/figlet-utf8 to provide /usr/bin/figlet (figlet) in auto mode

If you hit a broken state, work through the fixes in this order and stop at the first one that clears it:

  1. Run sudo dpkg --configure -a to finish anything half-configured.
  2. Run sudo apt --fix-broken install to fetch missing dependencies.
  3. Run sudo apt-get check and confirm it exits without listing unmet dependencies.

Never delete /var/lib/dpkg/lock-frontend to get past “Could not get lock”. apt’s own error warns against it, and the lock means another process (often unattended-upgrades right after boot) is mid-transaction. Wait for it, or see the lock behaviour in the apt vs apt-get section.

Use apt history to Undo an Install

apt 3.1 added a transaction history you can act on, the closest thing Debian systems have had to dnf history undo. It ships with Ubuntu 26.04, while Ubuntu 24.04 and Debian 13 do not have it yet. Before this, undoing an install meant reading /var/log/apt/history.log and retyping the package list by hand, which is how people end up removing the wrong library. List the transactions first.

sudo apt history-list

Transaction 7 was the apt install ./fortune-mod...deb run that pulled three packages. history-undo 7 reverses exactly that transaction and nothing else:

apt history-list showing eight transactions and apt history-undo 7 removing fortune-mod, fortunes-min and librecode3

The undo removes packages but does not purge them, so config files stay behind. Always read a transaction with history-info before reversing it, because the ID alone tells you very little. On the lab VM, sudo apt history-info 2 turned out to be the 216-package image upgrade with a new kernel in it, which is not something to undo casually. apt --help on apt 3.2 also lists history-redo and history-rollback.

apt why answers the other common question: what pulled this library in? It walks the dependency chain back to something you installed:

apt why libonig5

The trace shows jq as the reason, so removing jq makes libonig5 an autoremove candidate:

libonig5:amd64 is selected for install because:
1. jq:amd64 is selected for install
2. jq:amd64 Depends libonig5 (>= 6.8.1)

A trace that stops at (root) with no dependency chain under it usually means nothing installed needs the package. On the lab box that was pollinate, the same package apt upgrade kept flagging for autoremove, so cross-check with apt rdepends --installed before removing anything. On apt 2.x, apt rdepends --installed libonig5 and /var/log/apt/history.log give you the same answers with more reading.

Choose Between apt and apt-get

Use apt at the terminal and apt-get (plus apt-cache) in scripts, Dockerfiles and Ansible shell tasks. Both drive the same libapt and dpkg, so they install identical packages. The difference is the interface, and the apt(8) manual says plainly that apt’s output can change between versions while apt-get’s stays stable. apt even warns you when you pipe it:

apt list --installed | head -3

The warning goes to stderr, ahead of the package lines:

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Listing...
3cpio/resolute,now 0.14.0-1ubuntu1 amd64 [installed,automatic]
adduser/resolute,now 3.153ubuntu1 all [installed,automatic]

The lock is where the two behave most differently. With another process holding the dpkg lock, apt-get failed instantly with exit code 100, while apt sat on “Waiting for cache lock” and kept counting:

apt-get failing at once on a held dpkg lock-frontend while apt prints Waiting for cache lock and keeps waiting

Failing fast is usually what a script wants, but a provisioning run that starts while unattended-upgrades is busy then dies on boot. Add -o DPkg::Lock::Timeout=60 so apt-get waits like apt does. In scripts, also set the noninteractive frontend so no debconf prompt can block the run:

sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq cowsay

The rest of the differences, side by side:

Behaviouraptapt-get / apt-cache
Meant forPeople at a terminalScripts, CI, config management
Output formatCan change between releases (apt 3 added the Summary block)Stable, safe to parse
Held dpkg lockWaits with a counter (indefinitely in a terminal, 120 s when not on a TTY)Fails with exit 100 unless DPkg::Lock::Timeout is set
Pagerlist, show, search and policy open in a pager on apt 3Never
Progress bar and colourYesNo
Search and showapt search, apt showapt-cache search, apt-cache show
Upgrade with removalsapt full-upgradeapt-get dist-upgrade
History, why, satisfyYes on apt 3.1+No

apt-get is not deprecated and isn’t going away, because it is the scripting interface. If the pager gets in your way in a terminal, set APT_PAGER=cat in your shell profile. The equivalent cheat sheet for Fedora is the DNF5 commands cheat sheet, and the add-apt-repository guide covers adding PPAs and third-party repos.

Check Which apt Your Release Ships

Most commands on this page work on any supported release. The newer ones don’t, so check apt --version first and match it to this table, built from the Ubuntu and Debian package archives and the apt changelog:

Releaseapt versionSummary output and pagerapt why / why-nothistory-list / undo
Ubuntu 22.04 LTS2.4.15NoNoNo
Ubuntu 24.04 LTS2.8.4NoNoNo
Debian 122.6.1NoNoNo
Debian 133.0.3YesNoNo
Ubuntu 26.04 LTS3.2.1YesYesYes

Only the Ubuntu 26.04 row was run hands-on for this page. The other versions come from packages.ubuntu.com and tracker.debian.org in November 2026, and the feature columns follow the apt changelog: the pager arrived in 2.9.18, why in 3.1.0, history in 3.1.6 and undo in 3.1.7. Fresh from install? The Ubuntu 26.04 server post-install checklist puts these commands to work.

More printable references for Linux and DevOps tools live on the cheat sheets page.

Keep reading

Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) Ubuntu Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Security UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) AI Claude Code Cheat Sheet: Commands, Shortcuts and Flags (PDF) Upgrade a Single Package on Ubuntu / Debian with apt Debian Upgrade a Single Package on Ubuntu / Debian with apt CapRover Docker Install on Debian 13: Deploy Your First App Containers CapRover Docker Install on Debian 13: Deploy Your First App How To Install MongoDB 7.0 on Ubuntu 22.04|20.04 Databases How To Install MongoDB 7.0 on Ubuntu 22.04|20.04

Leave a Comment

Press ESC to close