Listing installed packages on Ubuntu becomes important as soon as a workstation, server, or VM has lived through several updates. A clean package inventory helps you spot what changed, rebuild another machine, and avoid guessing before cleanup or migration work.
The same APT and dpkg package-listing commands work on Ubuntu 26.04 LTS, 24.04 LTS, and 22.04 LTS, but output headers and APT warning text can differ. Use apt list --installed for fast interactive checks, dpkg --list for package state, dpkg-query for repeatable reports, and apt-mark when cleanup depends on manual versus automatic install flags. Snap and Flatpak apps live outside the dpkg database, so check those managers separately when they are present.
Choose the right command to list installed packages on Ubuntu
If you are troubleshooting dependency issues, checking free space, preparing a migration baseline, or planning a rebuild, an installed package list is your source of truth. A single flat list can hide useful clues, so choose the command based on the question you need to answer.
| Goal | Best command | Why |
|---|---|---|
| Quickly see installed package names and versions | apt list --installed | Readable for human review, but not the best source for scripts |
| Read package status codes and verify broken states | LC_ALL=C dpkg --list | Shows state flags such as ii and rc with an ASCII header |
| Inspect one installed package or file owner | dpkg-query --status, dpkg-query --search | Confirms the local package record and which package owns a file |
| Build scripts and custom reports | dpkg-query --show --showformat='...' | Predictable fields without APT progress or warning text |
| Distinguish manually installed packages from dependencies | apt-mark showmanual, apt-mark showauto | Useful before pruning packages or rebuilding another system |
| Check packages managed outside APT | snap list, flatpak list --app | Shows store-managed apps that APT and dpkg do not report |
| Review recent package install history | grep or zgrep on /var/log/dpkg.log* | Shows recent package changes when log retention still covers them |
Use apt list for a fast Ubuntu package inventory
Start with apt list --installed when you need an on-screen inventory that includes package name, source pocket, version, architecture, and install marker.
apt list --installed
The output is meant for people, not automation. It may print APT’s unstable-CLI warning on stderr, so use dpkg-query later when a script needs stable fields. After any warning text, example package rows look like this:
Listing... accountsservice/resolute,now 23.13.9-8ubuntu5 amd64 [installed,automatic] acl/resolute,now 2.3.2-2 amd64 [installed,automatic] adduser/resolute,now 3.153ubuntu1 all [installed,automatic]
To limit output for quick review, combine apt list with the grep command in Linux. Redirecting stderr keeps APT’s scripting warning out of the filtered result:
apt list --installed 2>/dev/null | grep -i "^linux-image" | head -n 20
That filter focuses on installed kernel image packages. Change the quoted prefix to another package family, such as python3- or libssl, when you need a different slice.
Use dpkg to read Ubuntu package state flags
dpkg --list is better when package state matters. The first columns show the desired action, current status, and error state, so you can distinguish installed packages from removed packages that still leave configuration files behind.
LC_ALL=C dpkg --list | head -n 20
LC_ALL=C keeps the header in an ASCII format, which is useful on Ubuntu 26.04 and newer systems where localized output can use box-drawing characters. Typical states include ii for fully installed packages and rc for removed packages that still keep conffiles.
+-- Desired=Unknown/Install/Remove/Purge/Hold |+- Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend ||+ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) ||| Name Version Architecture Description +++-==========================================-==========================================-============-================================================================================ ii accountsservice 23.13.9-8ubuntu5 amd64 query and manipulate user account information ii acl 2.3.2-2 amd64 access control list - utilities ii adduser 3.153ubuntu1 all add and remove users and groups
For a compact list of only fully installed packages, switch to dpkg-query and filter for the ii state:
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\t${Version}\n' | grep '^ii' | head -n 40
dpkg-query skips the header row and keeps the output compact for scripts, audits, and diff checks.
To check one package without scanning the full inventory, pass the package name to dpkg-query. An installed package returns a line beginning with ii; no output usually means the package is absent or no longer fully installed.
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev} ${binary:Package} ${Version}\n' bash 2>/dev/null | grep '^ii'
The version field changes by Ubuntu release, but the installed-state prefix should stay visible:
ii bash 5.3-2ubuntu1
Inspect one installed package and its files
After you find a package in the inventory, inspect the local dpkg record before you troubleshoot dependencies, file paths, or configuration ownership. A narrow status filter keeps the important local metadata easy to scan:
dpkg-query --status bash | grep -E '^(Package|Status|Architecture|Version):'
Relevant fields look like this for an installed package:
Package: bash Status: install ok installed Architecture: amd64 Version: 5.3-2ubuntu1
List package files when you need to locate documentation or default configuration files:
dpkg-query --listfiles bash | grep -E '^/(etc/bash.bashrc|usr/share/doc/bash/copyright)$'
/etc/bash.bashrc /usr/share/doc/bash/copyright
Reverse the lookup with dpkg-query --search when you have a file path and need to know which package owns it:
dpkg-query --search /etc/bash.bashrc
bash: /etc/bash.bashrc
Use apt-mark to split manual and automatic Ubuntu packages
Before removing unused software, check which packages are marked manual. Manual packages usually represent choices made by an administrator, while automatic packages were pulled in as dependencies.
Show manually installed packages with apt-mark
apt-mark showmanual
Use this output before a migration to identify core packages and tools that were intentionally installed.
ca-certificates dash diffutils findutils grep gzip
For rebuild planning, save the manual list instead of exporting every dependency from dpkg. APT can pull dependencies back in when you install the selected manual packages on a new system.
apt-mark showmanual | sort > "$HOME/ubuntu-manual-packages.txt"
The redirect writes the list to ubuntu-manual-packages.txt and does not print package names on screen when it succeeds.
Use this file as a rebuild checklist. Review it before feeding it to another system because package names, transitional packages, and desktop defaults can change between Ubuntu releases.
Show automatically installed dependency packages with apt-mark
apt-mark showauto
Everything in this list should be reviewed as dependency state, not a purge queue. A package can be automatic and still required by another installed package.
accountsservice acl adduser adwaita-icon-theme alsa-base alsa-topology-conf
List Snap and Flatpak packages outside APT
APT, dpkg, and apt-mark focus on DEB packages managed through Ubuntu’s package database. Ubuntu Desktop commonly has Snap packages, and customized systems may also have Flatpak apps, so list those package managers separately before calling an inventory complete.
Use snap list only when the Snap command exists on the system:
if command -v snap >/dev/null 2>&1; then
snap list
else
echo "snap is not installed"
fi
Flatpak is not installed on Ubuntu by default. If you use Flathub applications and the command is missing, set up Flatpak first with the Flatpak installation guide for Ubuntu.
Use flatpak list --app for Flatpak applications:
if command -v flatpak >/dev/null 2>&1; then
flatpak list --app --columns=application,name,version,branch,origin
else
echo "flatpak is not installed"
fi
Create repeatable Ubuntu package reports with dpkg-query
When you need data ready for scripts, ticket attachments, or before-and-after comparisons, use field-level output and save it to a file you control.
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\t${Version}\t${Architecture}\n' | grep '^ii' | sort > "$HOME/installed-packages.tsv"
Get only package names and versions for quick diffs between baseline snapshots:
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\t${Version}\n' | grep '^ii' | cut -f2- | sort > "$HOME/installed-baseline.txt"
When you only need the package count, count installed-state rows instead of counting every package record in dpkg’s database:
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\n' | grep -c '^ii'
The command prints one number. The total depends on the system role and installed software:
1504
After saving two snapshots, compare them with diff:
diff -u "$HOME/installed-before.txt" "$HOME/installed-after.txt"
Review recent Ubuntu package changes from logs
Current package lists show what is installed now. When you need to know when software changed, inspect the local package logs. The current dpkg log is usually enough for recent install events:
grep " install " /var/log/dpkg.log | tail -n 20
Recent install entries include the timestamp, package name, architecture, previous state, and installed version:
2026-05-07 13:57:45 install curl:amd64 <none> 8.18.0-1ubuntu2.1 2026-05-07 13:57:45 install libfuse2t64:amd64 <none> 2.9.9-9build1
To include rotated logs, use zgrep and ignore missing compressed files:
zgrep -h " install " /var/log/dpkg.log* 2>/dev/null | tail -n 40
Log retention varies by system, so treat this as recent history rather than a complete lifetime package inventory.
Troubleshoot Ubuntu package list output
APT warns that apt list is not stable for scripts
If you pipe apt list --installed inside a script, APT can print this warning:
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
For interactive review, the warning is harmless. For automation, switch to dpkg-query with explicit fields:
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\t${Version}\n' | grep '^ii' | cut -f2- | sort
dpkg list output uses unexpected header characters
Ubuntu 26.04 can show a newer dpkg --list header style depending on locale. If you need plain ASCII output for documentation, email, or older terminals, force the C locale:
LC_ALL=C dpkg --list | head -n 20
Removed packages still appear in a package audit
If a package shows the rc state, it was removed but still has conffiles. That state is useful during cleanup, but it should not be counted as an active package install.
LC_ALL=C dpkg-query --show --showformat='${db:Status-Abbrev}\t${binary:Package}\n' | grep '^rc' | cut -f2
For a clean installed-only inventory, keep the grep '^ii' filter from the earlier dpkg-query examples.
Snap or Flatpak apps are missing from dpkg output
This is expected. dpkg and dpkg-query report DEB packages only. Use snap list for Snap packages and flatpak list --app for Flatpak applications when those managers are installed.
Next Ubuntu package maintenance steps
Once your package list is deterministic, save the baseline before changing the system. If you plan to update first, take the final inventory after the update completes, then review leftover dependencies only when you understand why they are no longer required.
To see installed APT packages that currently have available upgrades, run:
apt list --upgradable
If the list is empty after package metadata is current, Ubuntu does not see pending upgrades from the configured APT sources.
- Use Ubuntu package update and upgrade commands to align all records before maintenance.
- Use Ubuntu package removal workflows only after you confirm which entries are intentional.
- Use Ubuntu version checks when command output differs from one supported release to another.
Ubuntu package command references
Conclusion
A useful Ubuntu package inventory separates the quick APT view, the installed-state dpkg-query report, manual and automatic apt-mark flags, and any Snap or Flatpak apps managed outside APT. Save that baseline before updates or removals so each cleanup decision starts from current package state instead of memory.
Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>