Rust Coreutils Explained: What uutils Changes on Ubuntu and What Still Differs From GNU

Rust Coreutils Explained: What uutils Changes on Ubuntu and What Still Differs From GNU

Type ls on a current Ubuntu system and the program that answers is no longer GNU’s. Since Ubuntu 25.10, the basic commands every Linux user runs hundreds of times a day come from uutils, a rewrite of coreutils in Rust, and with Ubuntu 26.10 the switch is complete.

For most people nothing visible changes, which is the point. This guide covers what uutils is, why Canonical made the switch, where it still behaves differently from GNU, and how to check and change which one you are running.

What coreutils actually is

Coreutils is the package that provides the basic file, text, and shell utilities: ls, cp, mv, rm, cat, mkdir, chmod, chown, sort, uniq, head, tail, wc, date, env, tr, cut, and about a hundred more. On nearly every Linux distribution for thirty years, these have come from GNU coreutils, written in C.

Some common tools are not part of coreutils, so the switch does not touch them: grep, sed, awk, find, tar, and bash are separate packages, still GNU on Ubuntu.

What uutils is

uutils coreutils is a cross-platform reimplementation of GNU coreutils in Rust. Its explicit goal is to be a drop-in replacement: same commands, same options, same output. The project treats any behavioural difference from GNU as a bug and runs the GNU test suite against itself to find them.

It ships as a multi-call binary: one executable, with each command name pointing at it, deciding what to do based on how it was invoked. That is the same trick BusyBox uses.

ls --version | head -1
# uutils coreutils 0.x
readlink -f "$(command -v ls)"

Why Canonical switched

The stated reasons are:

Memory safety. Coreutils parse filenames, command-line arguments, and file contents constantly, often running as root in scripts. Rust removes whole classes of bugs, such as buffer overflows and use-after-free, at compile time. GNU coreutils is extremely well tested, so this is about reducing long-term risk rather than fixing a known crisis.

Maintainability. A modern codebase with a modern test suite is easier to attract contributors to.

Performance headroom. Some uutils commands use parallelism or faster I/O paths. cat, sort, and base64 can be significantly faster on large inputs. Others are roughly equal.

It is part of a broader trend at Canonical, which also adopted sudo-rs, and in parts of the kernel and desktop, where Mir’s input layer is now Rust.

The rollout, and the stumbles

Ubuntu releaseCoreutils
25.10uutils by default
26.04 LTSuutils, except cp, mv, and rm kept as GNU
26.10uutils for everything

The 26.04 exception is instructive. cp, mv, and rm were held back because of TOCTOU (time-of-check to time-of-use) problems: race conditions where the program checks a path, and something changes that path before the program acts on it. GNU coreutils handles these carefully using file-descriptor-relative system calls, and matching that exactly took time.

There were also real regressions along the way. In July 2026, a subtle incompatibility in uutils cp -L (follow symlinks) broke Ubuntu’s own image builds, and cp was temporarily reverted to GNU. A crash in env -S was assigned CVE-2026-35377 and fixed in uutils 0.8.0.

None of this is surprising for a rewrite of software this old and this widely scripted against. It is why the migration took three releases.

Where uutils still differs from GNU

Differences shrink with every release, but the categories that remain are predictable:

Error message wording. Scripts that grep for exact text such as No such file or directory usually still work, because both use the system error strings, but the surrounding text can differ. Never parse error messages if you can check exit codes instead. Our exit codes guide covers why.

Obscure GNU options. Rarely used flags are the last to be implemented. If a script uses something unusual, test it.

env -S escapes. uutils is stricter about which escape sequences it accepts in env -S strings, which is used in some shebang lines.

date parsing. GNU date -d accepts a remarkable range of free-form strings like “next thursday” or “2 weeks ago”. uutils supports most common forms, but exotic ones may still differ.

Locale-sensitive sorting. sort and ls ordering under non-C locales has been an area of ongoing work. If you need exact byte ordering, set LC_ALL=C regardless of implementation, as you should with GNU too.

Checking a script before it matters

The reliable way to compare is to run the same script under both implementations and diff the output. Containers make that easy without touching your system, because Debian still ships GNU coreutils:

# GNU coreutils
podman run --rm -v "$PWD:/w:Z" -w /w debian:stable ./myscript.sh > out-gnu.txt 2>&1

# uutils (Ubuntu 26.10 or later)
podman run --rm -v "$PWD:/w:Z" -w /w ubuntu:26.10 ./myscript.sh > out-rust.txt 2>&1

diff out-gnu.txt out-rust.txt

Swap podman for docker if that is what you have. To see exactly which files each implementation installs on your own machine, ask the package manager:

dpkg -l | grep coreutils
dpkg -L coreutils-from-uutils | grep bin | head

How Ubuntu wires it together

Ubuntu uses a provider package model. The essential coreutils package no longer contains binaries itself; it depends on exactly one of two protected providers, one pulling in the uutils binaries and one pulling in GNU’s. That lets you swap without breaking the dependency graph that every other package relies on.

# See which provider is installed
apt policy coreutils-from-uutils coreutils-from-gnu

# Switch to GNU
sudo apt install coreutils-from-gnu

# Switch back to Rust
sudo apt install coreutils-from-uutils

Package names have shifted between releases, so if those are not found, apt search coreutils-from lists what your release uses.

Should you switch back?

For almost everyone, no. uutils now passes the large majority of the GNU test suite, and Ubuntu has been running it by default for a year. If a specific script breaks, the better fix is usually to make the script less dependent on implementation details, and to report the difference upstream, since the uutils project treats it as a bug.

Switch back if you run something critical that you cannot test immediately, or if you hit a behaviour difference that blocks your work today. Swapping is cheap in both directions.

Other distributions

Fedora, Debian, Arch, and openSUSE still ship GNU coreutils by default. uutils is packaged on most of them as an optional install, typically with a uu- prefix so it can sit alongside GNU without replacing it:

sudo pacman -S uutils-coreutils   # Arch
uu-ls --version

That is the easiest way to try it without committing.

Frequently Asked Questions

What are Rust coreutils?

Rust coreutils, from the uutils project, is a reimplementation of the GNU coreutils package in Rust. It provides the same commands such as ls, cp, mv, cat, sort and date, and aims to behave identically, with any difference from GNU treated as a bug.

Which Ubuntu versions use Rust coreutils?

Ubuntu 25.10 was the first release to ship uutils by default. Ubuntu 26.04 LTS kept cp, mv and rm on the GNU versions because of unresolved race condition issues. Ubuntu 26.10 completes the migration, so every coreutils command is the Rust version.

How do I check whether I am running GNU or Rust coreutils?

Run ls —version. GNU prints a line mentioning GNU coreutils, while uutils prints a line mentioning uutils coreutils. You can also run readlink -f on the binary, since uutils ships a single multi-call binary that the individual command names point to.

Will my shell scripts break?

Almost all scripts work unchanged because uutils passes the large majority of the GNU test suite. Scripts most at risk are ones that parse exact error message text, rely on obscure GNU-only flags, or depend on edge cases in date, env -S, or cp with symlink options.

Can I switch back to GNU coreutils on Ubuntu?

Yes. Ubuntu keeps GNU coreutils in the archive as an alternative provider. Installing the gnu-coreutils provider package swaps the commands back, and installing the rust provider swaps them again. Both cannot be the active provider at once.

Is Rust coreutils faster than GNU coreutils?

Sometimes. Some commands such as cat, sort and base64 are measurably faster in uutils on large inputs, while others are about the same or slightly slower. For typical interactive use the difference is not noticeable. Memory safety, not speed, is the main reason for the switch.