When a filesystem is nearly full, the useful question is rarely “which directory is large?” It is “which bytes are safe to reclaim without breaking the service that owns them?” ncdu gets you to the first answer quickly. This guide keeps the second answer firmly in the operator’s hands.

What ncdu measures

  • By default, ncdu reports allocated disk usage—the filesystem blocks consumed—not merely the logical byte length.

  • Apparent size can be very different for sparse files, compressed filesystems, block sharing/reflinks, and metadata.

  • Hard-linked files require careful accounting because multiple names can reference the same inode/data.

  • The scan is a point-in-time walk. Files can grow, disappear, move, or remain allocated after unlinking while a process still has them open.

Install ncdu and record the version

Terminalbash
sudo apt update
sudo apt install ncdu
ncdu --version

Risk level: caution. Review the command before running it.

Why the version matters

  • Ubuntu/Debian package versions can differ from upstream, and ncdu 1.x/2.x do not expose every option identically.

  • ncdu --version belongs in an incident record when export formats, parallel scanning, compression, or configuration behavior matters.

  • APT keeps package ownership and security updates coherent with the operating system.

  • On Fedora/RHEL-family or Arch systems, use the distribution’s supported package manager/repository and verify its packaged version instead of copying a stale repository-enablement command.

First scan: your home directory

Terminalbash
ncdu -rr "$HOME"

A safe way to learn the interface

  • Arrow keys move through entries, Enter opens a directory, the left arrow returns, and q exits. Press ? for the bindings supported by your version.

  • -rr disables deletion and shell spawning, so an exploratory keystroke cannot remove content or launch an arbitrary shell from the browser.

  • The scan uses your normal permissions and may report read errors for inaccessible entries; those are incomplete data, not zero usage.

  • Sort and display modes can change what is visually prominent without changing filesystem allocation.

Investigate a full root filesystem without crossing mounts

Terminalbash
df -hT /
findmnt -R /
sudo ncdu -x -rr /

Why -x is the critical flag

  • df -hT / identifies the filesystem, capacity, free blocks, and type that triggered the alert.

  • findmnt -R / reveals nested mounts such as separate data volumes, bind mounts, containers, and network filesystems.

  • -x/--one-file-system prevents ncdu from crossing filesystem boundaries, avoiding double work and accidental scans of remote/pseudo mounts.

  • sudo improves visibility but also exposes filenames/metadata from every readable directory. Run it only on an authorized host and keep deletion/shell disabled.

Disk usage versus apparent size

Terminalbash
ncdu -x -rr --disk-usage /srv/data
ncdu -x -rr --apparent-size /srv/data

Use the view that matches the question

  • Disk usage answers “how many filesystem blocks does this tree consume?” and is the default cleanup view.

  • Apparent size answers “how many logical bytes do files claim?” and can be larger for sparse files or misleading for shared extents.

  • Neither view necessarily equals df, which operates at filesystem allocation level and includes structures/reserved space that a directory walk may not attribute.

  • Scanning twice is not a transactional comparison; active workloads may change between runs.

Exclude known trees without forgetting them

ncdu-excludes.txttext
# Avoid an intentionally separate backup tree
/backups
 
# Skip compiler caches that follow CACHEDIR.TAG via --exclude-caches
 

Example reviewable exclusion patterns for a specific scan.

Exclusions change the conclusion

  • Each pattern in an exclude file is a scan rule; test it on a small tree and keep it with the incident notes.

  • Excluded entries can remain visible but their contents/sizes are not fully counted, depending on option and version.

  • Do not exclude a known large tree merely to make the total look manageable. State its separately measured allocation.

  • --exclude-caches recognizes directories marked with CACHEDIR.TAG; a cache marker does not prove deletion is safe while an application is active.

Terminalbash
ncdu -x -rr --exclude-caches -X ncdu-excludes.txt /srv

What this scan omits

  • -X loads newline-separated patterns from the named file.

  • --exclude-caches skips contents of directories using the cache-directory tagging convention.

  • The command stays on /srv’s filesystem and disables interactive mutation.

  • Record the exclusion file alongside results so another engineer can reproduce the scope.

Export once, analyze without rescanning

Terminalbash
ncdu -x -o- /srv | gzip > srv-ncdu.json.gz
gzip -t srv-ncdu.json.gz
gzip -dc srv-ncdu.json.gz | ncdu -f-

Why the pipeline is portable and safer

  • -o- writes the scan export to standard output instead of opening the browser. The JSON export can be large because it records every discovered path.

  • gzip compresses the stream; gzip -t validates compressed-file integrity, not semantic completeness.

  • -f- imports from standard input. ncdu intentionally disables refresh, deletion, and shell actions for imported data because it may not describe the current local filesystem.

  • Export files reveal directory structure, filenames, sizes, and potentially extended metadata. Restrict access, retention, and transfer accordingly.

Scan a remote server, browse locally

Terminalbash
ssh storage01 'sudo ncdu -x -o- /var' | gzip > storage01-var.json.gz
gzip -dc storage01-var.json.gz | ncdu -f-

The data crosses a trust boundary

  • The remote ncdu version creates the export; the local version must understand its format. Record both versions.

  • SSH protects transport when host identity is verified, but the uncompressed stream and local archive still contain sensitive inventory.

  • A dropped connection can leave a partial gzip; integrity-test the file and confirm the remote command’s exit status before trusting results.

  • Browsing locally cannot delete remote files, which is a feature. Return to the server with a separately reviewed cleanup plan.

Why ncdu and df disagree

  • Deleted but open files: directory walkers cannot see an unlinked pathname, while the filesystem retains blocks until the process closes it. Use sudo lsof +L1 and restart/rotate the owning service safely.

  • Reserved blocks and filesystem metadata: df accounts at filesystem level; ncdu attributes reachable directory entries.

  • Permissions/read errors: an unprivileged scan cannot count inaccessible trees. Review scan errors rather than treating them as empty.

  • Mount boundaries: -x intentionally excludes other filesystems; confirm the mount containing the pressure.

  • Snapshots/reflinks/compression/deduplication: logical ownership and physical allocation may not map one-to-one to paths. Use filesystem-native tools.

  • Concurrent writes: databases, logs, downloads, and containers can change allocation during the scan.

Before pressing d

  • Identify the file’s owner: package, systemd service, container runtime, database, user, backup policy, or application cache.

  • Check open handles, retention policy, recent access/mtime, hard links, snapshots, replication, and recovery requirements.

  • Prefer the owner’s cleanup mechanism—logrotate, journal vacuuming, package cache command, container prune policy, database retention, or application UI—over deleting internal files.

  • Confirm the path and mount in another terminal with stat, findmnt --target, and a targeted du; do not rely on a truncated terminal label.

  • Move recoverable user data to a reviewed quarantine/trash when practical. System data may require a service-specific maintenance sequence instead.

  • Rescan the narrow target in a writable ncdu session only after the plan is approved. Read the confirmation prompt and verify free space plus service health afterward.

Performance and very large trees

  • -q/slow UI updates reduces screen refresh frequency; it does not make storage metadata traversal intrinsically faster.

  • ncdu 2 supports parallel scanning controls and newer compressed/binary export features; verify the local manual because distro versions differ.

  • Scan the filesystem that is actually full and use -x; scanning all mounts “just in case” increases load and muddies attribution.

  • Schedule large scans away from latency-sensitive workloads, especially on metadata-heavy, networked, or spinning storage.

  • For repeat investigations, retain scoped exports under policy and compare them with timestamps; do not mistake old inventory for live state.

Troubleshooting

  • `ncdu: command not found`: verify the package transaction and command -v ncdu; do not download an unrelated binary from a search result.

  • Permission denied/read errors: decide whether complete privileged visibility is necessary; rerun with authorized sudo and -rr, or document the blind spots.

  • Terminal display is broken: check TERM, terminal capabilities, SSH allocation, and locale; use export mode on constrained sessions.

  • Scan hangs on a path: inspect the mount and storage health. Network/FUSE mounts and failing disks can block metadata operations.

  • Export will not import: compare ncdu versions, validate compression, and preserve the original error/output before converting formats.

  • Space did not return after deletion: check open-deleted files, snapshots, trash/quarantine, delayed reclaim, and whether you cleaned the filesystem reported by df.

Primary references

  • The official ncdu project page tracks current releases and major 2.x export/scanning capabilities.

  • The upstream ncdu 2.8 manual documents one-filesystem, read-only, export/import, exclusion, size, compression, and interface options.

  • The official ncdu JSON export format explains what scan exports contain and how read errors are represented.