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:

  • duf needs Debian 12+ / Ubuntu 22.04+
  • dfc and gdu live in Ubuntu's universe repo — enable it on minimal/server installs with sudo add-apt-repository universe (or sudo apt install software-properties-common first)
  • du-dust (provides the dust binary) exists in recent releases only. If apt says "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:

  1. df -h — which filesystem?
  2. duf -inodes — bytes or inodes?
  3. ncdu -x / or dust -n 15 — which directory?
  4. 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.