Point it at a directory and it tells you what kind of project lives there. No config files, no setup — just file detection.
use project_detect::{detect, ProjectKind};
if let Some(kind) = detect(".") {
println!("{} project ({})", kind.label(), kind.detected_file());
// "Rust project (Cargo.toml)"
}- 32 ecosystems detected out of the box
- Priority-ordered — language-specific files win over generic build systems
- Ecosystem metadata — Node.js package manager, Flutter vs Dart, Stack vs Cabal, etc.
- Directory walking —
detect_walksearches up the directory tree for monorepo support - Artifact directories — know what to clean for every ecosystem
- Zero dependencies beyond
serde_json(for package.json parsing)
| Priority | File | Ecosystem | Label |
|---|---|---|---|
| 1 | Cargo.toml |
Rust | "Rust" |
| 2 | go.mod |
Go | "Go" |
| 3 | mix.exs |
Elixir | "Elixir" |
| 4 | pyproject.toml / setup.py / setup.cfg |
Python | "Python" |
| 5 | package.json |
Node.js | "Node.js" |
| 6 | build.gradle(.kts) or pom.xml + Kotlin sources |
Kotlin | "Kotlin" |
| 7 | build.gradle / build.gradle.kts |
Gradle | "Gradle" |
| 8 | pom.xml |
Maven | "Maven" |
| 9 | build.sbt |
Scala | "Scala" |
| 10 | Gemfile |
Ruby | "Ruby" |
| 11 | Package.swift |
Swift | "Swift" |
| 12 | *.xcworkspace / *.xcodeproj |
Xcode (Objective-C / Objective-C++) | "Xcode" |
| 13 | build.zig |
Zig | "Zig" |
| 14 | *.csproj / *.sln |
.NET | ".NET" |
| 15 | composer.json |
PHP | "PHP" |
| 16 | pubspec.yaml |
Dart / Flutter | "Dart" / "Flutter" |
| 17 | stack.yaml / *.cabal |
Haskell | "Haskell" |
| 18 | project.clj / deps.edn |
Clojure | "Clojure" |
| 19 | rebar.config |
Erlang | "Erlang" |
| 20 | dune-project |
OCaml | "OCaml" |
| 21 | cpanfile / Makefile.PL |
Perl | "Perl" |
| 22 | Project.toml |
Julia | "Julia" |
| 23 | DESCRIPTION / renv.lock |
R | "R" |
| 24 | *.nimble |
Nim | "Nim" |
| 25 | shard.yml |
Crystal | "Crystal" |
| 26 | v.mod |
V | "V" |
| 27 | gleam.toml |
Gleam | "Gleam" |
| 28 | *.rockspec |
Lua | "Lua" |
| 29 | MODULE.bazel / WORKSPACE |
Bazel | "Bazel" |
| 30 | meson.build |
Meson | "Meson" |
| 31 | CMakeLists.txt |
CMake | "CMake" |
| 32 | Makefile |
Make | "Make" |
use project_detect::{detect, ProjectKind};
let kind = detect("/path/to/project").unwrap();
println!("{}", kind.label()); // "Rust"
println!("{}", kind.detected_file()); // "Cargo.toml"use project_detect::detect_walk;
// Running from src/lib/ inside a Cargo workspace?
// detect_walk finds the Cargo.toml in the parent.
if let Some((kind, project_dir)) = detect_walk(".") {
println!("Found {} at {}", kind.label(), project_dir.display());
}use project_detect::{detect, ProjectKind, NodePM};
match detect(".") {
Some(ProjectKind::Node { manager: NodePM::Pnpm }) => println!("pnpm project"),
Some(ProjectKind::Dart { flutter: true }) => println!("Flutter app"),
Some(ProjectKind::Haskell { stack: true }) => println!("Stack project"),
Some(ProjectKind::Haskell { stack: false }) => println!("Cabal project"),
Some(kind) => println!("{}", kind.label()),
None => println!("No project detected"),
}use project_detect::detect;
if let Some(kind) = detect(".") {
for dir in kind.artifact_dirs() {
println!("Can remove: {dir}/");
}
// Rust: ["target"]
// Node.js: ["node_modules", ".next", ".nuxt", ".turbo"]
// Haskell (Stack): [".stack-work"]
}use project_detect::{node_has_script, node_has_bin, detect_node_workspace};
use std::path::Path;
let dir = Path::new(".");
if node_has_script(dir, "build") { /* has a build script */ }
if node_has_bin(dir) { /* has a bin field */ }
if let Some(packages) = detect_node_workspace(dir) {
for pkg in packages {
println!("{}: {}", pkg.name, pkg.dev_script);
}
}MIT