Skip to content
projectdetect · rs

rust · no unsafe · crates.io

Detect what kind of project a directory is.

A pure-Rust crate that answers what a directory is, finds every project root under a tree, and resolves which project a file belongs to — a faithful 1:1 port of the Go projectdetect.

MIT licensed · no unsafe · CEL support is an opt-in feature

main.rs
// what project type(s) is this directory?
for m in projectdetect::detect(".") {
    println!("{} via {}", m.r#type, m.indicator);
}

// go             via go.mod
// docker-compose via docker-compose.yml

what you get

Filesystem-first project detection, in Rust.

Types match on indicators — an exact filename, a basename glob, a subdirectory marker, or an optional CEL expression over the directory's files and subdirs.

Detect & find

detect(dir) reports every type this directory matches — a directory can be several at once. Registry::find walks a tree and returns every project root under it.

Resolve a file's project

resolve_for_path(file) walks up to the nearest ancestor project root. The Resolver keeps an interior-mutable cache so repeated look-ups over a tree stay cheap.

28 built-in types

Go, Node, Rust, Python, Ruby, Maven/Gradle, .NET, Terraform, Compose — plus Swift, PHP, Scala, CMake, Zig and eight static-site generators. Each declares its build-artefact dirs for collect_build_excludes.

Custom types in YAML

Load extra types from YAML — has_file, has_glob, has_subdir_glob, or cel. Configs are auto-discovered across a user-wide layer and a per-project .file-search-on/.

CEL is opt-in

The crate has no CEL dependency by default. Enable the cel cargo feature for cel: indicators — otherwise the interpreter and its transitive deps stay out of your build.

Pure Rust, no unsafe

Idiomatic and safe: Indicator is an enum, timeouts are Option<Duration> with an Arc<AtomicBool> cancel flag, and the root .gitignore is respected. Builds on Rust 1.85+.

coverage

Built-in project types.

28 types out of the box — languages, build tools, and static-site generators — with the same indicator semantics as the Go library. Extend the set with your own via YAML.

  • go
  • node
  • rust
  • python
  • ruby
  • java-maven
  • java-gradle
  • dotnet
  • terraform
  • docker-compose
  • swift
  • php
  • scala-sbt
  • scala-mill
  • cmake
  • autotools
  • r
  • zig
  • perl
  • matlab
  • hugo
  • jekyll
  • eleventy
  • astro
  • gatsby
  • mkdocs
  • docusaurus
  • pelican

usage

Walk a tree, or resolve a single file.

Find every project root under a directory, or ask which project a given file belongs to.

// Every project root under a tree.
use projectdetect::{Registry, FindOptions};

let reg = Registry::with_builtins();
let result = reg.find("/path/to/code",
                      &FindOptions::default())?;
for p in result.projects {
    println!("{}: {:?}", p.path.display(), p.types);
}
// Which project does this file belong to?
let reg = Registry::with_builtins();
if let Some((root, types)) =
    reg.resolve_for_path("src/main.rs")
{
    println!("part of {:?}", types);
}
# Custom types in YAML.
project_types:
  - name: my-stack
    indicators:
      - has_file: "my.config"
      - has_glob: "*.mytool"
      - cel: '"services" in subdirs'
// Load them into a registry.
let mut reg = Registry::with_builtins();
let n = reg.load_from_file("types.yaml")?;
// …or auto-discover user + per-project configs
reg.load_discovered()?;

install

Add it to your crate.

One dependency-light crate. CEL support is a cargo feature you enable only if you need it.

cargo cargo add projectdetect
cel cargo add projectdetect --features cel
docs https://docs.rs/projectdetect

Builds on Rust 1.85+ (the cel feature needs 1.86+). Published on crates.io.