The Question df -h Cannot Answer
Every Linux user knows the command. Disk fills up, you type:
df -h
It tells you which filesystem is nearly full. On my machine right now:
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p8 118G 55G 57G 49% /
/dev/nvme0n1p7 157G 77G 72G 52% /home
/dev/nvme0n1p9 1.5G 274M 1.3G 18% /boot
tmpfs 7.6G 8.0K 7.6G 1% /dev/shm
Useful. Incomplete. It answers which filesystem is full. It does not answer who filled it. df sees mount points, not directories. The next step is always a second command, and that is where most people stop — staring at raw du output, scrolling through thousands of lines.
This post is the tool list I wish someone had handed me earlier. Each tool below answers one specific question about disk space, and most of them do it prettier, faster, or with more detail than df -h ever could.
Install Everything First
All six tools in one pass. Package names differ per distribution — notably, dust ships as du-dust in repositories.
Debian / Ubuntu
sudo apt update
sudo apt install -y duf dfc ncdu gdu
sudo apt install -y du-dust
Notes:
dufneeds Debian 12+ / Ubuntu 22.04+dfcandgdulive in Ubuntu'suniverserepo — enable it on minimal/server installs withsudo add-apt-repository universe(orsudo apt install software-properties-commonfirst)du-dust(provides thedustbinary) exists in recent releases only. Ifaptsays "Unable to locate package":
sudo snap install dust # snap fallback
# or, with a Rust toolchain:
cargo install du-dust
Fedora
sudo dnf install -y duf dfc ncdu gdu du-dust
Everything is in Fedora's default repositories. No extras needed.
Rocky Linux / AlmaLinux / RHEL
Enterprise Linux keeps the interesting tools in EPEL. Enable CRB (CodeReady Builder) first, then EPEL:
sudo dnf config-manager --set-enabled crb # Rocky; AlmaLinux 9+: crb, AlmaLinux 8: powertools
sudo dnf install -y epel-release
sudo dnf makecache
sudo dnf install -y duf ncdu gdu dfc du-dust
If a package is missing from EPEL (dnf reports "No match for argument"), grab the prebuilt RPM from the project's GitHub releases:
# example: duf
wget https://github.com/muesli/duf/releases/download/v0.9.1/duf_0.9.1_linux_amd64.rpm
sudo rpm -Uvh duf_0.9.1_linux_amd64.rpm
Same trick works for .deb on Debian/Ubuntu with sudo apt install ./file.deb.
Availability Cheat Sheet
| Tool | Debian / Ubuntu | Fedora | Rocky / Alma (EPEL) |
|---|---|---|---|
duf |
12+ / 22.04+ | default repo | EPEL 9/10 |
dfc |
universe | default repo | EPEL or binary |
ncdu |
default repo | default repo | EPEL |
gdu |
12+ / 22.04+ universe | default repo | EPEL or binary |
du-dust (dust) |
recent releases; snap/cargo fallback | default repo | binary fallback |
Verify after install:
duf && dust --version && gdu --version && ncdu -v && dfc -v && iostat -V
1. duf — df, But Actually Readable
duf (Disk Usage/Free) is a drop-in replacement for df. Same data, grouped into boxes, sorted sensibly, with pseudo-filesystems separated from real devices.
Command:
duf
Output:
╭──────────────────────────────────────────────────────────────────────────────╮
│ 4 local devices │
├────────────┬────────┬────────┬───────┬───────────────┬──────┬────────────────┤
│ MOUNTED ON │ SIZE │ USED │ AVAIL │ USE% │ TYPE │ FILESYSTEM │
├────────────┼────────┼────────┼───────┼───────────────┼──────┼────────────────┤
│ / │ 117.6G │ 54.5G │ 57.0G │ ███ 46.4% │ ext4 │ /dev/nvme0n1p8 │
│ /boot │ 1.5G │ 273.3M │ 1.2G │ █ 17.8% │ vfat │ /dev/nvme0n1p9 │
│ /home │ 156.4G │ 76.9G │ 71.5G │ ███ 49.2% │ ext4 │ /dev/nvme0n1p7 │
│ /nix/store │ 117.6G │ 54.5G │ 57.0G │ ███ 46.4% │ ext4 │ /dev/nvme0n1p8 │
╰────────────┴────────┴────────┴───────┴───────────────┴──────┴────────────────╯
Useful parameters:
duf -only local # hide tmpfs, bind mounts, pseudo devices
duf -all # show everything, including network and loop devices
duf -inodes # inode usage instead of block usage
duf -json # machine-readable output for scripts
The -inodes mode deserves special mention. Filesystems rarely run out of bytes — they run out of inodes (millions of tiny files, often from caches or mail spools). df -h shows 40% usage while the filesystem refuses writes. duf -inodes shows the truth:
│ MOUNTED ON │ INODES │ IUSED │ IAVAIL │ IUSE% │ TYPE │ FILESYSTEM │
│ / │ 7864320 │ 2092923 │ 5771397 │ 26.6% │ ext4 │ /dev/nvme0n1p8 │
│ /home │ 10485760 │ 797497 │ 9688263 │ 7.6% │ ext4 │ /dev/nvme0n1p7 │
2. dfc — df With Bar Charts
Older than duf, still maintained, and it draws proportional bars inline. Good for reports.
Command:
dfc
Output:
FILESYSTEM (=) USED FREE (-) %USED AVAILABLE TOTAL MOUNTED ON
/dev/nvme0n1p8 [===========---------] 51.5% 57.0G 117.6G /
tmpfs [=-------------------] 0.1% 3.8G 3.8G /run
/dev/nvme0n1p8 [===========---------] 51.5% 57.0G 117.6G /nix/store
/dev/nvme0n1p7 [===========---------] 54.3% 71.5G 156.4G /home
/dev/nvme0n1p9 [====----------------] 17.8% 1.2G 1.5G /boot
Useful parameters:
dfc -l # locally mounted filesystems only (hides tmpfs clutter)
dfc -s # print total usage sum
dfc -T # add filesystem type column
dfc -W # never truncate long mount points
dfc -u M # sizes in mebibytes
dfc -e csv # export as CSV (other formats: read manpage)
Note: long mount points get truncated in narrow terminals. Widen the terminal or use dfc -W.
3. ncdu — Find the Directory Eating Your Disk
df says /home is 52% full. Which folder? This is where df ends and ncdu begins. It scans a directory tree and opens an interactive browser — navigate with arrow keys, sort by size, delete in place.
Command (interactive):
ncdu -x /
Parameters worth knowing:
ncdu -x /home # one filesystem only — never cross into mounts
ncdu -x --exclude=.cache /home/nixos
ncdu -2 / # force full ncurses UI (for odd terminals)
ncdu -o scan.json /home # scan now, browse later (or on another machine)
ncdu -f scan.json # re-open a saved scan
-x (--one-file-system) is the important flag. Without it, ncdu happily re-scans every mount under the path — network shares, backup drives, /proc. On a big server that turns a 10-second scan into a 10-minute one.
The interactive UI is the main event, but ncdu also exports scans for scripting or remote review:
ncdu -x -o /tmp/scan.json /etc
Output (exported scan, head):
[1,2,{"progname":"ncdu","progver":"2.11.1","timestamp":1790658169},
[{"name":"/etc","asize":4096,"dsize":4096,"dev":66312},
{"name":"os-release","asize":22,"notreg":true},
{"name":"sudoers","asize":383,"dsize":4096},
[{"name":"tmpfiles.d","asize":4096,"dsize":4096},
[{"name":"systemd.conf","asize":35,"notreg":true},
4. gdu — ncdu for Big Disks
ncdu is single-threaded. On a multi-terabyte SSD that feels slow. gdu (written in Go) scans with parallel workers and finishes in a fraction of the time. Same idea, same keybindings, much faster.
Command (interactive):
gdu /
Command (non-interactive):
gdu --depth 1 /etc
Output:
3.5 MiB /etc
3.4 MiB /etc/nixos
8.0 KiB /etc/passwd-
4.0 KiB /etc/systemd
4.0 KiB /etc/sudoers
Useful parameters:
gdu --depth 2 /home # non-interactive, depth 2 (fast text output)
gdu --ignore-dirs=/var/cache /var
gdu --min-age 7d /home # only files modified in last week
gdu -D scan.sqlite / # save scan to database for later re-browse
Rule of thumb: ncdu on a laptop home directory, gdu on a server full of data.
5. dust — du, But You See the Big Picture First
du -sh * gives you a list. dust gives you a tree, sorted by size, with bars — top consumers visible immediately, no scrolling.
Command:
dust -n 15 /home/nixos
Output:
26Gi ┌─┴ TEMP │███████████████████████████████ │ 100%
8.7Gi ├─┴ ISO_for_Pentest │█████████ │ 33%
4.5Gi │ ├── WIN10.PRO.AIO...ISO │██████░░░░ │ 17%
4.2Gi │ ├── Win10-PU29...7z │██████░░░░ │ 16%
4.1Gi ├─┴ Windows Apps Installer │██████ │ 16%
3.2Gi │ ┌── iPhone11Plus │████ │ 12%
2.0Gi ├── Documents │███ │ 10%
Useful parameters:
dust -n 10 / # only top 10 entries
dust -d 2 /home # limit depth
dust -x /home # stay on one filesystem
dust -X /path/to/skip /home # exclude path
dust -p /home # full paths instead of shortened names
dust -F /home # only files — find the single biggest file
dust -D /home # only directories
dust answers "what are the biggest things here" in one screen. ncdu answers "let me walk the tree and clean up". Different jobs.
6. lsblk and findmnt — The Block-Device View
Sometimes the problem is not usage — it is layout. Wrong partition, tiny /boot, swap where you expected data. lsblk shows the disk as a tree with filesystem types and usage:
Command:
lsblk -f
Output:
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
nvme0n1
├─nvme0n1p1 vfat FAT32 SYSTEM 62F3-6BE0
├─nvme0n1p3 ntfs OS 3E6CF54A6CF4FE09
├─nvme0n1p6 swap 1 e0ca924a-0085-451d-8a27-0d58d10f67b9 [SWAP]
├─nvme0n1p7 ext4 1.0 27ad332d-2300-4af8-bd01-aa0c41c34132 71.5G 49% /home
├─nvme0n1p8 ext4 1.0 70f4fe8f-76e4-40ae-bd0d-cc62ee395ea5 57G 46% /nix/store
│ /
└─nvme0n1p9 vfat FAT32 7C58-261B 1.2G 18% /boot
Useful parameters:
lsblk -f # filesystem types, UUIDs, usage
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS # custom columns
lsblk -p # full device paths
When lsblk is not enough, findmnt gives the mount table with usage numbers:
findmnt -D
SOURCE FSTYPE SIZE USED AVAIL USE% TARGET
/dev/nvme0n1p8 ext4 117.6G 54.5G 57G 46% /
/dev/nvme0n1p7 ext4 156.4G 76.9G 71.5G 49% /home
/dev/nvme0n1p9 vfat 1.5G 273.3M 1.2G 18% /boot
findmnt /home # what backs this mount?
findmnt -t ext4,nfs # filter by filesystem type
7. One-Liners for Exotic Filesystems
df and duf only see what the kernel reports. Some filesystems expose richer tools:
zpool list # ZFS pools: size, alloc, free
zfs list # ZFS datasets with quotas
btrfs filesystem usage / # Btrfs: data/metadata/system split
vgs # LVM volume groups: free PE
lvs # LVM logical volumes
df -h --total # sum all local filesystems (GNU df)
stat -f /home # raw statvfs: free/available blocks
df -h --total is the hidden gem of the coreutils version — one total row across every listed filesystem, handy in scripts:
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p8 118G 55G 57G 49% /
/dev/nvme0n1p7 157G 77G 72G 52% /home
...
total 297G 132G 151G 47% -
Which Tool When
| Situation | Run |
|---|---|
| Quick check, terminal only | df -h |
| Pretty overview | duf |
| Bars + percentages in one line | dfc |
| Disk full, suspect a folder | ncdu -x / or gdu / |
| Huge server, slow scan | gdu (parallel) |
| "What's biggest here" at a glance | dust -n 15 /path |
Writes fail but df shows space free |
duf -inodes |
| Partitioning / mount layout questions | lsblk -f, findmnt -D |
| NFS/SMB share full, need remote view | df -h -t nfs |
| Disk slow, not full | iostat -x 1 5 |
Command Cheat Sheet
| Tool | Command | What it shows |
|---|---|---|
df |
df -h |
baseline GNU output |
df |
df -h --total |
same, plus total row |
duf |
duf |
boxed grouped table |
duf |
duf -inodes |
inode exhaustion view |
dfc |
dfc |
inline bar charts |
ncdu |
ncdu -x /home |
interactive browser |
gdu |
gdu / |
interactive fast scanner |
gdu |
gdu --depth 1 /etc |
non-interactive text |
dust |
dust -n 15 /home/nixos |
tree with bars |
lsblk |
lsblk -f |
partition tree |
findmnt |
findmnt -D |
mount table with usage |
iostat |
iostat -x 1 5 |
I/O throughput (not capacity) |
For interactive tools (ncdu, gdu), output lives in the terminal UI — the non-interactive variants above give paste-able text. Wide tables clip at 80 columns; 120+ keeps them intact.
Closing
df -h is not wrong. It is just the first question, not the answer. The workflow that actually frees disk space:
df -h— which filesystem?duf -inodes— bytes or inodes?ncdu -x /ordust -n 15— which directory?- Delete, move, or expand.
Install the whole set in one line: sudo apt install duf dfc ncdu gdu du-dust on Debian/Ubuntu, sudo dnf install duf dfc ncdu gdu du-dust on Fedora (EPEL first on Rocky/Alma). One minute of setup saves the next hour of guessing.
Have a disk-full war story? Share it in the comments.