Check Disk Usage on Linux: df, du and ncdu Explained
On this page
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.
/ 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 withsudo du -sh /var/log/* | sort -h. - The systemd journal.
journalctl --disk-usageshows its size andsudo journalctl --vacuum-size=200Mtrims it. - Package caches:
sudo apt cleanorsudo dnf clean all. - Old backups and archives nobody remembers making, often in home directories or
/root. - Docker images, containers and volumes:
docker system df, thendocker system pruneonce 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.
/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
| Goal | Command |
|---|---|
| Free space on real disks | df -h -x tmpfs -x devtmpfs |
| Which disk holds a path | df -h /var |
| Inode usage | df -i |
| Size of a directory | du -sh dir |
| Subdirectories by size | du -h -d 1 | sort -h |
| Top 20 items | du -ah . | sort -rh | head -20 |
| Stay on one filesystem | du -xh -d 1 / |
| Interactive browser | ncdu -x / |
| Files over 500 MB | find / -xdev -type f -size +500M |
| Journal size | journalctl --disk-usage |
| Deleted but open files | sudo lsof +L1 |