Check Disk Usage on Linux: df, du and ncdu Explained

System · 7 min read · Updated 25 Oct 2026

On this page
  1. df: free space per filesystem
  2. Out of inodes
  3. du: how big is this directory?
  4. Why du and ls disagree
  5. ncdu: browse disk usage interactively
  6. Find large files directly
  7. The usual suspects
  8. Deleted files that still use space
  9. Quick reference

A full disk breaks things in confusing ways: databases refuse writes, logins hang, package updates fail halfway and editors cannot save. When it happens you need two answers quickly. Which filesystem is full, and what is filling it? df answers the first question, du and ncdu answer the second.

df: free space per filesystem

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             16G     0   16G   0% /dev
tmpfs           3.2G  2.9M  3.2G   1% /run
/dev/sda1       628G  181G  415G  31% /
tmpfs            16G  2.3M   16G   1% /dev/shm

-h prints human-readable sizes. The column that matters is Use% for real disks, here /dev/sda1 mounted on /. The tmpfs and udev lines are in memory, and you can hide them:

$ df -h -x tmpfs -x devtmpfs
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       628G  181G  415G  31% /

To check only the filesystem holding a particular directory, give the path: df -h /var or df -h .. Add -T to show the filesystem type, and use --output to choose columns for scripts:

$ df -h --output=source,pcent,target -x tmpfs -x devtmpfs
Filesystem     Use% Mounted on
/dev/sda1       31% /

Do not be surprised if Used plus Avail is less than Size. ext4 reserves about 5% of the disk for root by default, so the system can keep working when ordinary users have filled the rest.

Out of inodes

If writes fail with "No space left on device" while df -h shows free space, check inodes. Every file uses one, and a filesystem has a fixed number:

$ df -i /
Filesystem       Inodes   IUsed    IFree IUse% Mounted on
/dev/sda1      41885696 2719575 39166121    7% /

Running out of inodes usually means millions of tiny files: PHP session files, mail queues, cache directories or a runaway script. GNU du --inodes -d 1 counts files per directory instead of bytes, which points at the culprit.

du: how big is this directory?

$ du -sh project
132K	project
$ du -sh *
4.0K	list.txt
48K	backup-2026-10-25.tar.gz
132K	project

-s gives a single total for each argument, -h makes it readable. Note that * skips hidden files and directories; use du -sh .[!.]* * to include them.

The most useful form shows one level of subdirectories, sorted so the biggest comes last:

$ du -h -d 1 project | sort -h
8.0K	project/logs
116K	project/src
132K	project

-d 1 (the same as --max-depth=1) limits the depth, and sort -h understands suffixes like K, M and G. Repeat the command in the biggest directory and you will find the problem in a few steps. To list the largest files and directories anywhere under a path:

$ du -ah project | sort -rh | head -5
132K	project
116K	project/src
108K	project/src/nums.txt
8.0K	project/logs
4.0K	project/src/a.txt

Other handy options are -x to stay on one filesystem (so scanning / does not wander into /proc, network mounts or other disks), -c to add a grand total, and --exclude='*.log' to skip a pattern.

Scanning / or /home on a big server can take minutes and hammer the disk. Start with sudo du -xh -d 1 /, then drill into the directory that stands out instead of running du -a on everything.

Why du and ls disagree

ls -l shows a file's apparent size, the number of bytes in it. du shows the disk space actually allocated, which is rounded up to whole blocks and can be much smaller for sparse files:

$ truncate -s 1G sparse.img
$ ls -lh sparse.img | awk '{print $5}'
1.0G
$ du -h sparse.img
0	sparse.img

Virtual machine images and database files are often sparse. Use du --apparent-size if you want du to report the same figures as ls.

ncdu: browse disk usage interactively

ncdu scans a directory once and then lets you move around the results with the arrow keys, biggest items first. Install it with sudo apt install ncdu or sudo dnf install ncdu, then run:

$ ncdu /var
$ sudo ncdu -x /

Use Up and Down to select, Enter to open a directory, Left to go back, n and s to sort by name or size, g to toggle the percentage graph, i for details and q to quit. d deletes the selected item after asking for confirmation, so be careful when running it as root.

On a slow or busy server, you can scan once to a file and browse later: ncdu -x -o scan.json / writes the results, and ncdu -f scan.json opens them without rescanning.

Find large files directly

Sometimes you want a list of big files rather than a tree. find does that well:

$ find . -xdev -type f -size +10M -exec ls -lh {} +
-rw-r--r-- 1 alice alice 12M Oct 25 02:34 ./big.bin

Change the starting point and size to suit, for example sudo find / -xdev -type f -size +500M. The find guide has many more size and age filters.

The usual suspects

  • Logs in /var/log, especially an application logging every request or a log that rotation never touches. Check with sudo du -sh /var/log/* | sort -h.
  • The systemd journal. journalctl --disk-usage shows its size and sudo journalctl --vacuum-size=200M trims it.
  • Package caches: sudo apt clean or sudo dnf clean all.
  • Old backups and archives nobody remembers making, often in home directories or /root.
  • Docker images, containers and volumes: docker system df, then docker system prune once you know what it will remove.

Deleted files that still use space

If you delete a big log and df does not change, a running process probably still has the file open. The space is only released when the process closes it. lsof lists such files:

$ sudo lsof +L1

Look for entries marked (deleted) and restart the service that owns them. To empty a log that a process is still writing to, truncate it instead of deleting it: sudo truncate -s 0 /var/log/app.log. Restarting processes is covered in the process management guide.

Never delete files from /var/lib, /usr or database directories just because they are big. Find out what owns them first. Removing a database's data files or a package manager's state can do far more damage than a full disk.

Quick reference

GoalCommand
Free space on real disksdf -h -x tmpfs -x devtmpfs
Which disk holds a pathdf -h /var
Inode usagedf -i
Size of a directorydu -sh dir
Subdirectories by sizedu -h -d 1 | sort -h
Top 20 itemsdu -ah . | sort -rh | head -20
Stay on one filesystemdu -xh -d 1 /
Interactive browserncdu -x /
Files over 500 MBfind / -xdev -type f -size +500M
Journal sizejournalctl --disk-usage
Deleted but open filessudo lsof +L1