Library / SDK
camino-rs/camino avatar
camino-rs/camino

camino: UTF-8 path types for Rust, and the cases where they are wrong

Like Rust's std::path::Path, but UTF-8.

581 stars28 forksRustApache-2.0

At a glance

What is it?
camino is a thin Rust crate that adds Utf8Path and Utf8PathBuf beside the standard library's Path types, so a program can guarantee its paths are UTF-8 and skip the to_str().unwrap() habit. The README is unusually direct about when not to use it, including for core system utilities, for Git tooling and for disk recovery utilities.
Who is it for?
camino suits a Rust application that assumes UTF-8 paths, works cross-platform, or has to read path strings out of files such as a Cargo.toml, and for those cases the crate removes a class of runtime failure rather than adding a layer. It is the wrong tool for a core system utility, for software that has to handle arbitrary Git repositories, and for anything that must cope with potentially corrupt filenames, and the README says all three explicitly.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 38 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The standard library leaves a hole, camino fills it

The library's own tagline is the shortest statement of the idea: like Rust's std::path::Path, but UTF-8. The mechanism is that camino adds Utf8PathBuf and Utf8Path types, which are like the standard library's PathBuf and Path types except that they are guaranteed to only contain UTF-8 encoded data. They therefore expose the ability to get their contents as strings, they implement Display, and so on. The reasoning about why the standard library does not do this is worth reading, because it explains what you are trading. The std::path types are not guaranteed to be valid UTF-8, and the README calls that the right decision for the standard library since it must be as general as possible. However, on all platforms, non-Unicode paths are vanishingly uncommon for a number of reasons, and the first of them is that Unicode is now the dominant encoding for file names, with only some legacy codebases still storing paths in encodings like Shift JIS. The second is that Unicode is the common subset of supported paths across Windows and Unix, and the third is that there are already many systems, such as Cargo, that only support UTF-8 paths.

The makefile problem is the real argument

The fourth reason in the list is the one that generalises beyond Rust. The makefile problem asks: given a Makefile or other metadata file, such as a Cargo.toml, that lists the names of other files, how should the names in the Makefile be matched with the ones on disk? The answer in the README is that this has no general, cross-platform solution in systems that support non-UTF-8 paths, and that restricting paths to UTF-8 eliminates the problem. That is a sharper claim than the usual UTF-8 argument, because it is not about display or convenience but about whether a build system can be correct at all. The consequence for the programmer follows directly. Many programs that want to manipulate paths do assume they contain UTF-8 data, and convert them to strs as necessary, but because that invariant is not encoded in the Path type, conversions such as path.to_str().unwrap() need to be repeated again and again, creating a frustrating experience. Camino's pitch is to let you check that your paths are UTF-8 once, and then manipulate them as valid UTF-8 from there on, avoiding repeated lossy and confusing conversions.

A drop-in replacement with three deliberate differences

camino is described as a very thin wrapper around std::path, and Utf8Path and Utf8PathBuf are drop-in replacements for Path and PathBuf. Most APIs are the same, but those at the boundary with str are different, and the README names the changes. Path::to_str() returning an Option<&str> has been renamed to Utf8Path::as_str() returning a &str, so the Option disappears because it can no longer be None. Utf8Path implements Display, and Path::display() has been removed, so printing a path no longer needs a method call. And iterating over a Utf8Path returns &str rather than &OsStr, which is the change that touches the most call sites in practice. One compatibility guarantee does hold. Every Utf8Path is a valid Path, so Utf8Path implements AsRef<Path>, and any API that accepts an impl AsRef<Path> will continue to work with Utf8Path instances. The consequence is that migrating is mostly mechanical: change the type names, and fix the places where the compiler now points at a str boundary that used to be an OsStr.

Adding it to a project, and what the manifest pins

The crate is added to a Cargo manifest like any other dependency, and because it has no default dependencies there is nothing to fetch beyond the standard library. The crate's own manifest records the constraints a dependent inherits, and the fields worth knowing are the version policy and the edition:

toml
rust-version = "1.61.0"
toml
edition = "2021"

The licence field in the same manifest is MIT OR Apache-2.0, which is the dual licensing that lets a downstream project pick either. The first use of the types in your own code is a type swap, and the compiler points at the three str boundary differences described earlier. After that, the documentation for Utf8PathBuf and Utf8Path contains several examples, and the camino-examples directory shows how the types are used with other libraries like serde and clap, which is where to look for the integration pattern rather than reinventing it. The crate is published on crates.io as camino, so the dependency line names that package and not the repository.

When the README says not to use it

The section on whether to use camino is the most useful part of the documentation, and it cuts both ways. You should consider using camino if you are building portable, cross-platform software, because while both Unix and Windows platforms support different kinds of non-Unicode paths, Unicode is the common subset supported across them. You should use it if your system has files that contain the names of other files, which is the makefile problem again. You should use it if you are interacting with existing systems that already assume UTF-8 paths, since in that case you will not be adding any new burdens on downstream consumers. And you should use it if you are building something brand new and are willing to ask your users to rename their paths if necessary. Against that, you should not use camino if you are writing a core system utility, and the example given is an mv or cat replacement, where you should use std::path::Path and add extensive tests for non-UTF-8 paths. You should not use it if you have legacy compatibility constraints, and Git is named as a system that supports non-UTF-8 paths, in which case the tool should use its own path type wrapping a Vec<u8>, with the caveat that std::path::Path supports arbitrary bytestrings on Unix but not on Windows. And you should not use it if you need to support non-UTF-8 paths for some other reason, with disk recovery utilities given as the case where only handling UTF-8 paths would greatly diminish their utility.

No dependencies by default, and a conservative MSRV

By default, camino has no dependencies other than std, and the optional features are the only source of dependencies. The serde1 feature adds Serialize and Deserialize implementations for Utf8PathBuf and Utf8Path, and the README flags them as zero-copy, which is the point of using a string-backed path type rather than a byte-backed one. The proptest1 feature adds proptest Arbitrary implementations for Utf8PathBuf and Box<Utf8Path>, which is what you want if you are property-testing code that builds paths. The version policy is the other thing to note. The minimum supported Rust version for camino with default features is 1.61, and the project is tested in CI against the latest stable version and the MSRV. Stable APIs added in later Rust versions are supported either through conditional compilation in build.rs or through backfills that also work on older versions, deprecations are kept in sync with the version they were added in, and unstable APIs are currently not supported, with the README asking for a GitHub issue if one is needed. Camino is designed to be a core library and has a conservative MSRV policy, and MSRV increases will only happen for a compelling enough reason.

Packaging, licensing and where the code lives

The crate is published on crates.io as camino at version 1.2.6, with documentation on docs.rs, and the licence is MIT OR Apache-2.0, with both LICENSE-MIT and LICENSE-APACHE files in the repository root. The Cargo manifest shows the details that matter for a library others depend on. The package is a workspace of its own with a single member, it is edition 2021 with rust-version 1.61.0, and its include list is deliberately narrow, covering build.rs, the src and tests directories, the changelog, the two licence files and the readme, so the published package does not carry the repository's own working files. The docs.rs metadata asks for all features to be built with the --cfg=doc_cfg rustdoc argument, which is how the feature-gated APIs get documented properly. The release process is automated through release.toml and a set of pre-release replacements in the package metadata that rewrite the changelog's Unreleased heading and link template on each release. The authors listed are Without Boats, Ashley Williams, Steve Klabnik and Rain, and the repository includes a camino-examples directory showing how the types are used with libraries like serde and clap, which is where to look if you want the pattern for your own code.

Editorial conclusion

camino suits a Rust application that assumes UTF-8 paths, works cross-platform, or has to read path strings out of files such as a Cargo.toml, and for those cases the crate removes a class of runtime failure rather than adding a layer. It is the wrong tool for a core system utility, for software that has to handle arbitrary Git repositories, and for anything that must cope with potentially corrupt filenames, and the README says all three explicitly. Verify first whether your inputs can actually contain non-UTF-8 bytes, because if they can, adopting camino is a decision to reject those paths rather than to handle them, and note that the crate is Apache-2.0 and MIT licensed, with a 1.61 minimum supported Rust version that makes it unusually cheap to depend on.

Frequently asked questions

What is camino and what problem does it solve?

It is a Rust crate that adds Utf8Path and Utf8PathBuf types alongside the standard library's Path and PathBuf, with the guarantee that they contain only UTF-8 encoded data, so their contents can be read as strings and you stop repeating to_str().unwrap() conversions.

When should I not use camino?

The README says not to use it for core system utilities such as an mv or cat replacement, where you should use std::path::Path and add extensive tests for non-UTF-8 paths. It also says not to use it with legacy compatibility constraints such as handling arbitrary Git repositories, or where you need non-UTF-8 path support for another reason, such as disk recovery utilities.

What are the API differences from std::path?

Most APIs are the same, but the str boundary differs. Path::to_str() returning Option<&str> is renamed to Utf8Path::as_str() returning &str, Utf8Path implements Display so Path::display() has been removed, and iterating over a Utf8Path yields &str rather than &OsStr.

Does camino have dependencies?

By default it has no dependencies other than std. The optional features add them: serde1 adds Serialize and Deserialize implementations for Utf8PathBuf and Utf8Path, described as zero-copy, and proptest1 adds proptest Arbitrary implementations for Utf8PathBuf and Box<Utf8Path>.

What Rust version does camino require?

The minimum supported Rust version with default features is 1.61, and the project is tested in CI against the latest stable release and the MSRV. Stable APIs added in later Rust versions are supported through conditional compilation in build.rs or through backfills, while unstable APIs are not currently supported.

Official sources

  1. camino-rs/camino on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/camino-rs-camino.svg)](https://hysenlabs.com/projects/camino-rs-camino)

Was this useful?