TechEarl

duf: A Friendlier df for Disk Usage

duf is a df replacement that prints grouped, color-coded disk usage tables instead of df's raw columns. Install it, filter to the devices you care about, sort by usage, and pipe --json into scripts.

Ishan Karunaratne⏱️ 9 min readUpdated
Share thisCopied
duf is a df replacement that prints grouped, color-coded disk usage tables. Install it, filter local devices with --only local, sort by --sort usage, hide mounts with --hide-mp, and emit --json for scripts.

duf is a df replacement that prints your mounted filesystems as grouped, color-coded tables instead of df's raw whitespace columns. Run duf with no arguments and it shows you local disks, network mounts, and special filesystems in separate boxes, each with a usage bar and percentages already worked out. It is one statically-linked Go binary, so there is nothing to configure and nothing to learn beyond a handful of filter flags.

The reason to reach for it: df -h dumps every loop device, every tmpfs, and every snap mount into one undifferentiated list, and you end up squinting to find the one disk that is actually filling up. duf groups those by type and colors the nearly-full ones, so the disk you care about jumps out. Everything below is install, filtering, sorting, and the --json output that makes it scriptable.

Install duf

duf is packaged on most distributions now, so you rarely need to grab a binary by hand.

bash
# Debian 12+ / Ubuntu 22.04+
sudo apt install duf

# Fedora
sudo dnf install duf

# Arch
sudo pacman -S duf

# macOS
brew install duf

It ships in the Debian and Ubuntu repos from the versions above; on an older release you install the .deb from the GitHub releases page instead. There is no daemon, no config file, and no root requirement for reading mount info. Once installed, just run it.

The default output

bash
duf
code
╭───────────────────────────────────────────────────────────────────────────╮
│ 2 local devices                                                             │
├──────────────┬────────┬────────┬───────┬───────────────────────────┬───────┤
│ MOUNTED ON   │   SIZE │   USED │ AVAIL │ USE%                      │ TYPE  │
├──────────────┼────────┼────────┼───────┼───────────────────────────┼───────┤
│ /            │ 117.0G │  78.4G │ 32.6G │ [######............] 67.0% │ ext4  │
│ /boot        │   1.0G │ 213.0M │ 787.0M│ [####..............] 20.8% │ ext4  │
╰──────────────┴────────┴────────┴───────┴───────────────────────────┴───────╯

Each group is its own table with a heading like 2 local devices. The USE% column is a literal bar, and on a real terminal it is colored: green well under, amber as it climbs, red when a disk is nearly full. That coloring is the single biggest reason duf beats reading df columns; you do not have to compare numbers by eye to spot the problem.

Filter to the devices you care about

By default duf groups filesystems into local, network, fuse, special, loops, and binds. On a developer laptop the special and loops groups are noise, so scope the output to what matters.

bash
# only the real, physical disks
duf --only local

# only local plus network mounts, skip everything else
duf --only local,network

--only takes a comma-separated list of those group names and shows nothing else. Its inverse is --hide:

bash
# everything except the loop devices and special filesystems
duf --hide loops,special

You can also filter by filesystem type or by mount point directly:

bash
# only tmpfs and vfat filesystems
duf --only-fs tmpfs,vfat

# only the root and home mount points
duf --only-mp /,/home

# hide a noisy mount point (wildcards work)
duf --hide-mp '/snap/*'

--only-mp and --hide-mp support glob wildcards like /sys/*, which is the clean way to drop a whole tree of pseudo-mounts. The opposite of scoping down is --all, which adds the pseudo, duplicate, and inaccessible filesystems that duf hides by default. I reach for --all maybe once a year, when I am chasing a bind mount that is not showing up.

Sort and pick columns

duf sorts by mount point by default. The flag I use constantly is --sort usage, which floats the fullest disk to the top.

bash
duf --sort usage

--sort accepts mountpoint, size, used, avail, usage, type, filesystem, and the inode variants. If you only want certain columns, --output takes the same kind of list:

bash
duf --output mountpoint,size,used,avail,usage

For inode exhaustion (the classic "disk has free space but writes fail" case), --inodes swaps the block columns for inode counts. That one has saved me more than once on a box that was out of inodes from millions of tiny session files while df -h still showed gigabytes free.

Pipe duf into scripts with --json

duf is for humans, but --json makes it scriptable too.

bash
duf --json | jq '.[] | select(.mount_point=="/") | .used'
code
84198547456

The JSON is an array of objects, one per filesystem, with named fields like mount_point, total, used, free, inodes, device, fs_type, and type. (Note the field names are total/free, not the SIZE/AVAIL column headers from the table, and there is no precomputed usage field in the JSON, so you derive the percentage yourself from used / total.) That is cleaner to parse than scraping df columns with awk, because you get raw bytes and named fields instead of pre-formatted human strings you have to un-format. For a monitoring check, duf --json --only local | jq is a tidy one-liner. When duf's output is not a terminal (a pipe, a redirect to a file, a cron job), it drops the colors and the box-drawing on its own, so you do not need a --no-color flag; reach for --json when you want structure and let the plain table fall out automatically when you do not.

duf vs df vs ncdu

These three get confused. They solve different problems.

ToolWhat it answersReadsBest for
dfHow full is each mounted filesystemMount tableUniversal, always present, scriptable
dufSame, but readable and groupedMount tableQuick eyeball check of which disk is full
ncduWhich directories are eating the spaceWalks the treeHunting down what to delete

duf and df answer the same question (per-filesystem usage) and read the same kernel mount data, so they are interchangeable for the "is the disk full" check. duf just renders it better. ncdu is a different job entirely: it walks a directory tree to tell you which folders are big, which is what you run after duf tells you / is at 95%. If you are tracking down the actual files, see how to find the largest files on disk.

When to stick with df

duf is the nicer daily driver, but it is not always the right call.

  • Scripts that must run anywhere. df is in every POSIX environment with zero install. A shell script you ship to servers you do not control should use df (or duf --json only where you can guarantee the binary is present).
  • A genuinely minimal container or recovery shell. If you are in a busybox initramfs or a scratch image, df is there and duf is not. Do not add a dependency for a one-off check.
  • Muscle memory in a hurry. During an incident, df -h is the thing your fingers already know. duf is worth installing on machines you live in, not memorizing under pressure.

For everything else (your workstation, dev boxes, anywhere you read disk usage by eye more than once a week), duf earns its place. Pair it with a modern ls replacement like exa/eza for richer directory listings, and a syntax-highlighting cat replacement like bat, and the whole "where did my space go" loop gets faster.

One install gotcha worth knowing: oh-my-zsh's common-aliases plugin defines duf='du -sh *', which shadows the binary if you have that plugin enabled. Run unalias duf (and drop it in your .zshrc after the oh-my-zsh load line) so the real command wins.

See also

FAQ

duf is a disk usage utility that prints your mounted filesystems as grouped, color-coded tables, where df prints plain whitespace columns. Both read the same kernel mount data and answer the same question, how full each filesystem is. The difference is presentation: duf separates local disks from network and special mounts, draws a usage bar per filesystem, and colors the nearly-full ones so the disk that needs attention stands out.

Run duf --only local. By default duf groups filesystems into local, network, fuse, special, loops, and binds, and shows them all. --only local hides everything except the physical disks. You can list several groups, like duf --only local,network, or use the inverse --hide loops,special to drop just the noise.

Yes. duf --json emits an array of objects with raw-byte fields like mount_point, total, used, and free, which you parse with jq instead of scraping df columns through awk. For example, duf --json | jq '.[] | select(.mount_point=="/") | .used' returns the used bytes on root. It is cleaner than parsing the human-formatted table.

Yes. Install it with brew install duf. It runs on macOS, the BSDs, Windows, and Android/Termux in addition to Linux, because it is a single statically-linked Go binary. The flags are the same across platforms; only the set of filesystem groups you actually see differs by OS.

No, they answer different questions. duf reads the kernel mount table and tells you how full each filesystem is, the same data df reports, just rendered as grouped color tables. ncdu walks a directory tree and tells you which folders and files are eating the space. The usual flow is to run duf first to see that, say, / is at 95%, then run ncdu / (or find the largest files on disk) to track down what to delete.

Run duf --sort usage. By default duf sorts by mount point; --sort usage floats the fullest filesystem to the top of each group. The flag also accepts size, used, avail, type, filesystem, and the inode variants. Combine it with --only local to sort just your real disks.

oh-my-zsh's common-aliases plugin defines duf='du -sh *', which shadows the installed binary if that plugin is enabled, so typing duf runs the alias instead of the program. Run unalias duf to remove it for the current session, and add that line to your .zshrc (after the oh-my-zsh load line) so the real command wins in every new shell.

Sources

Authoritative references this article was fact-checked against.

TagsdufdfCLIDisk UsageLinuxmacOSShell Scripting

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

Rank the biggest files on a full disk with find -printf '%s %p' piped to sort -rn. The GNU one-liner, the BSD stat variant for macOS, why -xdev matters, human-readable sizes, and when du or ncdu beats find.

How to Find the Largest Files on Disk (find, sort, du)

find / -xdev -type f -printf '%s %p\n' | sort -rn | head -20 gives you a ranked list of the biggest files on a full disk. The GNU one-liner, the BSD/macOS stat variant, why -xdev matters, human-readable output with numfmt, when to switch to du or ncdu for per-directory totals, and the mistakes that send a scan into /proc.

Divi's Dynamic Content binds ACF fields to module properties. Setup, patterns for Text and Image, limits for Repeater and Flexible Content, escape hatches.

Using ACF with Divi for Dynamic Content

Divi's Dynamic Content lets editors bind ACF field values to module properties without leaving the visual builder. The setup, the patterns that work for Text and Image fields, the limits for Repeater and Flexible Content, and the custom-shortcode escape hatch.