apt

Install, remove and update Debian packages

Updated 2026-08-18

apt is the command you will type more than any other on a Debian system. It resolves dependencies, fetches packages from the repositories configured in /etc/apt/sources.list.d/, and hands them to dpkg to unpack and configure, then keeps the whole set consistent as things change underneath it.

The naming is genuinely confusing, so it is worth being precise. apt is one of several front ends to the same library: apt-get and apt-cache are the older, script-stable pair, and apt gathers the most-used parts of both behind one name with nicer defaults. They are shipped by the same package and share a dependency resolver, so they never disagree about what should be installed. apt vs apt-get covers where they do differ.

Underneath sits dpkg, which installs a single .deb file and knows nothing about repositories, dependencies or where a package came from. Almost every apt command ends in a dpkg run, which is why dpkg's errors surface through apt.

The two-step model

Nearly every mistake with apt comes from forgetting that it works from a cached copy of what the repositories contain, not from the repositories themselves:

  • apt update refreshes that cache. It changes nothing about what is installed.
  • apt install / apt upgrade act on the cache as it currently stands.

So apt install immediately after a fresh install of Debian, without an apt update first, can fail to find a package that is right there in the archive, or offer you a version that was superseded weeks ago. When something is missing or stale, apt update is nearly always the first thing to try. Debian's release channels covers what those repositories are and how a package gets into one.

Seeing what will happen first

Every state-changing apt command prints its plan and waits for confirmation. Read the plan rather than skipping to the y/n. It tells you what is about to be installed, upgraded, removed and, the line worth reading twice, what is no longer required.

-s (--simulate, also spelled --dry-run) goes further: it prints the plan and exits without touching anything, needing no root. Use it whenever a command is going to remove something, or when you are working from instructions you do not fully trust.

Which one is safe in a script

apt is designed for people. It says so itself: run any apt command with its output piped somewhere and it prints a warning that its command-line interface is not stable between versions. In a script, in a Dockerfile, in a systemd unit or in cron, use apt-get and apt-cache, whose output formats are treated as an interface and kept still. Add -y, set DEBIAN_FRONTEND=noninteractive, and check the exit status; see Exit codes and error handling.

Scripts also have to cope with not being the only thing installing packages: on a machine running automatic updates, apt can fail outright because something else holds the dpkg lock. Could not get lock /var/lib/dpkg/lock-frontend explains the timeout that fixes it properly.

Root, and when you don't need it

Anything that changes installed packages needs root, normally through sudo, which on Debian is not always installed, depending on what you answered about a root password when you set the machine up. Anything that only reads (search, show, list, policy, and any --simulate run) does not, and it is worth getting into the habit of running those unprivileged. The examples below mark which is which.

18 outputs, collapsed by default

Finding a package

None of these change anything, so none need sudo. All of them read the local cache built by apt update rather than asking the repositories directly. The examples on this page act on cowsay throughout, because it is small, it is Architecture: all - so its output is identical on every machine - and removing it breaks nothing.

Search for a package by name and description

apt search 'talking cow' | head -6

Full-text search across names and descriptions - neither package here is called "talking cow". It matches generously, so pipe it through head.

Show output
Sorting...
Full Text Search...
cowsay/stable,now 3.03+dfsg2-8 all [installed]
  configurable talking cow

cowsay-off/stable 3.03+dfsg2-8 all

Search package names only

apt search --names-only '^cowsay'

Restricts the match to the package name, and takes a regular expression - ^ anchors it to the start. See grep for the syntax.

Show output
Sorting...
Full Text Search...
cowsay/stable,now 3.03+dfsg2-8 all [installed]
  configurable talking cow

cowsay-off/stable 3.03+dfsg2-8 all
  configurable talking cow (offensive cows)

Read a package's details

apt show cowsay | head -12

Version, size, dependencies and homepage. The full output also ends with the repository it came from and the long description; -a shows every available version rather than just the candidate.

Show output
Package: cowsay
Version: 3.03+dfsg2-8
Priority: optional
Section: games
Maintainer: James McDonald <james@jamesmcdonald.com>
Installed-Size: 94.2 kB
Depends: libtext-charwidth-perl, perl:any
Suggests: filters, cowsay-off
Homepage: https://web.archive.org/web/20120527202447/http://www.nog.net/~tony/warez/cowsay.shtml
Tag: game::toys, implemented-in::perl, interface::commandline, role::program,
 use::entertaining, works-with::text
Download-Size: 21.4 kB

Check whether a package is installed

apt list --installed cowsay cowsay-off

Names several packages at once. Only the installed ones are listed, so a package missing from the output is one that isn't installed.

Show output
Listing...
cowsay/stable,now 3.03+dfsg2-8 all [installed]

List installed packages matching a pattern

apt list --installed 'ca-cert*'

Quote the pattern, or the shell tries to expand it as a filename first and apt never sees it.

Show output

Your output will differ: the ca-certificates version changes with each Debian point release

Listing...
ca-certificates/stable,now 20250419 all [installed]

See which version apt would install

apt policy cowsay | head -3

Installed: is what you have and Candidate: is what a plain apt install would give you. The rest of the output lists each available version and the repository offering it.

Show output
cowsay:
  Installed: 3.03+dfsg2-8
  Candidate: 3.03+dfsg2-8

Show what a package depends on

apt depends cowsay

Direct dependencies only. Depends: is required, Recommends: is installed by default on Debian, and Suggests: never is.

Show output
cowsay
  Depends: libtext-charwidth-perl
  Depends: <perl:any>
    perl
  Suggests: filters
  Suggests: cowsay-off

Seeing what apt will do before it does it

-s (--simulate, or --dry-run) prints the plan and exits without changing anything. It needs no root, which makes it the safe way to read instructions you don't fully trust.

Simulate an install

apt install -s cowsay-off

Shows what would be installed, including dependencies pulled in behind the package you named.

Show output

Your output will differ: the point release in Debian:13.6 and the Not Upgrading count move as the archive does

Reading package lists...
Building dependency tree...
Reading state information...
Installing:
  cowsay-off

Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 1
Inst cowsay-off (3.03+dfsg2-8 Debian:13.6/stable [all])
Conf cowsay-off (3.03+dfsg2-8 Debian:13.6/stable [all])

Simulate a removal

apt remove -s cowsay

The line to read is anything under REMOVED - this is where an unexpected cascade shows up before it happens rather than after.

Show output

Your output will differ: the point release in Debian:13.6 and the Not Upgrading count move as the archive does

Reading package lists...
Building dependency tree...
Reading state information...
The following packages were automatically installed and are no longer required:
  libgdbm-compat4t64  libperl5.40  perl  perl-modules-5.40
Use 'apt autoremove' to remove them.

REMOVING:
  cowsay

Summary:
  Upgrading: 0, Installing: 0, Removing: 1, Not Upgrading: 1
Remv cowsay [3.03+dfsg2-8]

Simulate an install without the recommended extras

apt install -s --no-install-recommends cowsay-off

Debian installs Recommends: by default. Comparing this against the plain simulate above shows exactly what that policy adds.

Show output

Your output will differ: the point release in Debian:13.6 and the Not Upgrading count move as the archive does

Reading package lists...
Building dependency tree...
Reading state information...
Installing:
  cowsay-off

Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 1
Inst cowsay-off (3.03+dfsg2-8 Debian:13.6/stable [all])
Conf cowsay-off (3.03+dfsg2-8 Debian:13.6/stable [all])

See which packages are no longer needed

apt autoremove -s

Lists packages installed automatically as dependencies that nothing requires any more. Worth reading before running the real thing.

Show output

Your output will differ: the point release in Debian:13.6 and the Not Upgrading count move as the archive does

Reading package lists...
Building dependency tree...
Reading state information...
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 1

Installing packages

All of these need root. -y answers the confirmation prompt in advance, which a script needs and which is worth omitting by hand so you get a chance to read the plan. Their output is a live download - sizes, speeds, and the architecture of your own machine - so it isn't reproduced here.

Install a package

sudo apt install cowsay-off

Fetches the package and everything it depends on, then configures the lot. Prints the plan and waits for confirmation first.

Install several packages in one transaction

sudo apt install -y cowsay-off bash-completion

Naming them together makes it a single transaction, so dependencies are resolved across the whole set and it either all succeeds or all fails.

Install a specific version

sudo apt install cowsay-off=3.03+dfsg2-8

Pins this install to a version apt policy lists. apt refuses if another installed package needs a different one.

Install without the recommended extras

sudo apt install --no-install-recommends cowsay-off

Keeps the install minimal - sensible in a container image, and on a desktop often removes something you wanted.

Download a package without installing it

apt download cowsay

Drops the .deb in the current directory and needs no root. Useful for moving a package to a machine with no network, or inspecting it before trusting it.

Install a .deb file you already have

sudo apt install ./cowsay_3.03+dfsg2-8_all.deb

Prefer this over dpkg -i, because apt resolves the file's dependencies from the repositories. The ./ matters - without it, apt looks for a package with that name instead. Installing a .deb by hand has the failure mode and the way out of it.

Removing packages

remove and purge differ only in what happens to the configuration in /etc, and that difference is behind most of the "I removed it but it's still configured" confusion. autoremove is not a third strength of the same operation: it acts on packages you never asked for, a distinction pulled apart here.

Remove a package, keeping its configuration

sudo apt remove cowsay

Deletes the programs, leaves the configuration files in place, and the package then shows as rc rather than gone. Reinstalling later picks your settings back up.

Finish a removal you meant as a purge

sudo apt purge -y bash-completion

Acts on a package already in the rc state, where the programs are gone but the configuration is not. This is the fix for having run remove when you wanted purge.

Remove packages nothing needs any more

sudo apt autoremove

Deletes packages pulled in as dependencies that are now unreferenced. Read apt autoremove -s first - it occasionally proposes something you installed deliberately.

Keeping the system up to date

Two separate steps, and conflating them is the most common apt mistake. update refreshes the local list of what exists and installs nothing; the upgrade commands act on whatever that list currently says. Their output depends on what Debian has published this week, so it isn't reproduced here either.

Refresh the package lists

sudo apt update

Contacts each configured repository and rebuilds the local cache. Run it before installing on a machine that has been idle, or apt works from stale information.

Upgrade, allowing packages to be removed

sudo apt full-upgrade

The same operation as apt-get dist-upgrade. Allowed to remove packages to satisfy a dependency change, which a release upgrade needs and a routine update does not.

List the packages with upgrades waiting

apt list --upgradable

Read-only, so no sudo. Shows the installed version and the candidate side by side - the quickest way to judge whether an upgrade is worth doing now.

Upgrade one package and nothing else

sudo apt install --only-upgrade cowsay

Upgrades just the named package. It often refuses, which is apt telling you the upgrade isn't really a single-package job.

Holds, marks and disk space

List every held package

apt-mark showhold

Worth checking when an upgrade refuses to install something for no visible reason - a forgotten hold is a common cause.

Show output
ca-certificates

Release a hold

sudo apt-mark unhold ca-certificates

Returns the package to normal upgrade handling, and says so only if a hold was really in place.

Show output
Canceled hold on ca-certificates.

Mark a package as automatically installed

sudo apt-mark auto cowsay

Tells apt you didn't ask for this one directly, making it eligible for autoremove once nothing depends on it.

Show output
cowsay set to automatically installed.

Delete downloaded package files

sudo apt clean

Empties /var/cache/apt/archives. Frees real space on a long-lived machine, and costs only re-downloading anything you reinstall.

apt in scripts

Use apt-get and apt-cache here rather than apt: their output is treated as a stable interface and apt's explicitly is not. See apt vs apt-get.

Install with no prompting at all

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

-y answers apt's own prompt; DEBIAN_FRONTEND=noninteractive stops a package's configuration script opening a dialogue behind it and hanging for ever.

Print just the installed version of a package

dpkg-query -W -f='${Version}\n' cowsay

dpkg-query -f is the scriptable way to read package metadata: you name the fields, so nothing else in the output can shift underneath you.

Show output
3.03+dfsg2-8

Fix a half-finished install

sudo apt install -f

Short for --fix-broken. Completes dependency work left unfinished by an interrupted run, and is the first thing to try when apt refuses to do anything else.