# gdu: a disk usage analyzer that admits SSDs are the point

> A Go replacement for ncdu and dust that leans on parallel scanning, ships a terminal UI plus a web UI, and defaults to ignoring the virtual filesystems that slow every other scanner down.

**dundee/gdu** — Fast disk usage analyzer with console interface written in Go

- Repository: https://github.com/dundee/gdu
- Stars: 5,998 · Forks: 234
- Language: Go
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/dundee-gdu

## Installing a single static binary with curl

The README's install path is a release binary and nothing to compile:

```bash
curl -L https://github.com/dundee/gdu/releases/latest/download/gdu_linux_amd64.tgz | tar xz
chmod +x gdu_linux_amd64
mv gdu_linux_amd64 /usr/bin/gdu
```

The downloads are named per platform, so the macOS and Windows builds follow the same pattern with different asset names. Anything beyond that, including package manager installs, is pushed to a separate `INSTALL.md` at the repository root, and the README carries a Repology badge for tracking how many distributions package it.

There is also a container path, which matters because scanning a filesystem you do not own usually needs elevated privileges:

```bash
docker run --rm --init --interactive --tty --privileged --volume /:/mnt/root ghcr.io/dundee/gdu /mnt/root
```

Note the flags. `--privileged` plus mounting the host root is how the analyzer sees the real filesystem rather than the container's view of it, and the image is published to GitHub Container Registry under the same owner as the source. The `Dockerfile` in the repository builds from `golang:1.26.1` and then assembles a `FROM scratch` image with a single copied binary, so the container carries no shell and no package manager.

## Why parallelism is the whole argument

The README states the design intent directly: gdu is intended primarily for SSD disks where it can fully utilize parallel processing, and it notes that HDDs work as well but the performance gain is not so huge. That is an unusually honest framing for a performance tool, and it tells you which machine to expect the speedup on.

The `go.mod` shows how the parallelism is achievable. The Go version is 1.26.0, and the storage layer pulls in `github.com/dgraph-io/badger/v4` for BadgerDB alongside `modernc.org/sqlite`, a pure Go SQLite implementation that needs no cgo. That cgo-free property is what allows the release build to be static, and the `Makefile` confirms it by setting `CGO_ENABLED=0` in both the `build` and `build-static` targets.

There is a second, smaller performance lever visible in the same file: a committed `default.pgo`, referenced in the Makefile as `-pgo=default.pgo`. Profile-guided optimization ships with the repository rather than being generated per build, so the compiler is given real profile data from the maintainer's own workload.

## Persisting scans to SQLite or BadgerDB

The flag list includes `-D, --db string`, documented as storing the analysis in a database with `*.sqlite` for SQLite and `*.badger` for BadgerDB, and paired with `-r, --read-from-storage` to use an existing database instead of re-scanning.

That pair is the feature that most distinguishes gdu from ncdu, and it changes what the tool is for. A one-shot scan answers a question and is discarded. A stored scan can be reopened days later, which is what makes gdu usable for tracking a directory over time rather than only cleaning it once.

The release history shows this area getting real attention. v5.36.0, published 2026-04-27, lists a top-dir analyzer for non-interactive mode plus implementation of deletion, JSON encoding and query optimizations for SQLite storage. v5.36.1, published 2026-04-29, follows two days later with refinements to the SQLite backend, an analyzer refactor, optimizations to the top directory analyzer, and a fix that improves SQLite storage and the analyzer implementation. Three commits in two days on the same subsystem is a good indication of where the author found the remaining rough edges.

## The web UI added in v5.37.0, and its security note

The most recent release, v5.37.0 published 2026-08-18, adds a browser interface alongside the terminal one, and the help output now carries a flag for it:

```bash
      --web                            Run the web UI (serves a browser interface instead of the terminal UI)
      --web-listen string              Address for the web UI to lis
```

The release notes describe what happens next: you pass the flag and a directory, gdu scans it, prints the URL, and by default opens it in your default browser. The interface pairs an animated donut chart of the current directory with a sortable table with size bars, breadcrumb navigation, and a toggle between disk usage and apparent size, with scan progress streamed live while the analysis runs.

Two details are worth more attention than the feature itself. First, the compiled web assets are embedded in the binary, so there are no extra files to distribute and no network access required at runtime, The `Makefile` shows how that works: a `build-web` target compiles and minifies the React frontend into `webui/dist`, which is committed and embedded, and its comment notes that the pure-Go build targets do not need Node.js because they use the committed output. Second, the security paragraph is explicit: the web UI is read-only and has no authentication, it exposes file names and sizes over HTTP, the server binds to `localhost` on a random free port by default, and binding to a non-loopback address makes the exposure real. Use `--web-listen` or the `web.listen` config option to pin an address, and `--web-open=false` to print the URL without launching a browser.

## The flag surface for narrowing a scan

The help output is long because the filtering options are the substance of the tool, and they cluster into four groups worth naming.

Type filtering comes in pairs: `-T, --type` and `-E, --exclude-type` both take comma-separated extensions such as `yaml,json`. Age filtering is unusually complete, with `--max-age` and `--min-age` taking durations like `7d`, `2h30m` or `1y2mo`, plus `--since` and `--until` accepting RFC3339 timestamps or plain `YYYY-MM-DD` dates. Path exclusion has four separate mechanisms: `-i, --ignore-dirs` defaulting to `/proc,/dev,/sys,/run`, `-I, --ignore-dirs-pattern`, `-X, --ignore-from` reading patterns from a file, and `-G, --ignore-from-gitignore` reading `.gitignore`-style patterns.

That last one is the flag a developer will reach for first when measuring a repository. Storage behaviour is controlled by `--archive-browsing` for zip, jar and tar archives including the compressed tar variants, `-L, --follow-symlinks` for file symlinks only, and `-x, --no-cross` to stop at filesystem boundaries.

Two flags exist purely for safety. `--no-delete` disallows deletions outright, and `--no-spawn-shell` disallows spawning a shell, both of which matter more than they look if you point the tool at a directory you did not create. There is a `--trash-command` flag for routing deletions to `trash-put` instead of the built-in trash, and a `--config-file` flag defaulting to `$HOME/.gdu.yaml`.

## Repository layout and what it implies

The tree separates the three ways gdu can present results, which matches the flags above. `tui/` is the terminal interface and depends on `gdamore/tcell/v2` and `rivo/tview` in the module manifest. `webui/` holds the React frontend, and `stdout/` is the non-interactive path, which is where `--summarize`, `--depth`, `--top`, `--no-progress` and `--reverse-sort` all apply.

Underneath those sit `internal/`, `pkg/` and `cmd/gdu`. The `report/` directory produces the visualisations, which explains the CodeScene code health and CodeClimate maintainability badges on the README alongside Codecov coverage.

There is more documentation in the repository than the README suggests. Beyond `INSTALL.md` and `CONTRIBUTING.md` there is `configuration.md` for the YAML config file, a full manual page in `gdu.1.md` with the generated `gdu.1` alongside it, `gdu.spec` for RPM packaging and `snapcraft.yaml` for Snap. Two files stand out as unusual: `AGENTS.md` and `CONTEXT.md`, which suggest the author keeps working notes in the repository for coding agents, and a `.golangci.yml` for lint configuration. There is also `.tool-versions` and a `Dockerfile` at the root. The repository is not archived and the last push was on 2026-09-21, a month after v5.37.0 shipped.

## Conclusion

gdu is the disk usage tool to reach for when you are on an SSD and the usual suspects feel slow, which is most of the time on a modern machine. The parallel scanning is the reason, and the README is honest that the gain shrinks on spinning disks, offering a --sequential flag for rotating HDDs instead. Two features separate it from ncdu: scan results can be persisted to SQLite or BadgerDB and re-read without rescanning, and as of v5.37.0 the same data can be served as a web UI with an embedded donut chart. The one thing to read carefully before exposing that web UI is its own security note, since it is read-only, unauthenticated and reveals file names and sizes. Start with the curl one-liner, add --no-delete if you want a read-only survey, and keep the default localhost binding.

## FAQ

### What is a faster alternative to ncdu?

gdu is written as one. The README describes it as a pretty fast disk usage analyzer in Go, intended primarily for SSDs where it can fully use parallel processing, and notes that HDDs work too but with a smaller gain. There is a --sequential flag for rotating HDDs. It also adds scan persistence to SQLite or BadgerDB, which ncdu does not have.

### Is the gdu web UI safe to expose on a network?

The v5.37.0 release notes say the web UI is read-only, has no authentication, and exposes file names and sizes over HTTP, and that it binds to localhost on a random free port by default. Binding it to a non-loopback address makes that exposure real, so keep the default unless you have put authentication in front of it.

### How do I keep gdu from deleting anything?

Use --no-delete, which the help output describes as not allowing deletions. There is also --no-spawn-shell to prevent it opening a shell, and --trash-command if you would rather route deletions to a tool such as trash-put than to the built-in trash.

### Can gdu scan only certain file types?

Yes, with -T or --type and -E or --exclude-type, both taking comma-separated extensions such as yaml,json. Age filtering is separate: --max-age and --min-age take durations like 7d or 1y2mo, and --since and --until take RFC3339 timestamps or plain dates.

## Sources

- [dundee/gdu on GitHub](https://github.com/dundee/gdu)
- [Issues](https://github.com/dundee/gdu/issues)
- [License: MIT](https://github.com/dundee/gdu/blob/master/LICENSE)
- [README](https://github.com/dundee/gdu/blob/master/README.md)
- [Releases](https://github.com/dundee/gdu/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dundee-gdu
