pure go · no cgo · fs-based
Detect what kind of project a directory is.
A tiny Go library that answers two questions over a filesystem: what project type(s) does this directory look like, and what project roots live under a tree.
MIT licensed · zero cgo · CEL support is opt-in
// what project type(s) is this directory? for _, m := range projectdetect.Detect(fsys, ".") { fmt.Printf("%s via %s\n", m.Type, m.Indicator) } // go via go.mod // node via package.json // docker-compose via docker-compose.yml
what you get
Filesystem-first project detection.
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(fsys, dir) reports every type this directory matches — a directory can be several at once. Find(ctx, root, opts) walks a tree and returns every project root under it.
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 too.
Per-file language
A separate axis: LanguageForPath("src/app.py") → "python". A 1:1 extension→language map across 17 recognised languages, C++'s dozen spellings included.
Skip vendored & minified
IsVendored("docs/js/jquery.min.js") catches third-party content anywhere — patterns from GitHub Linguist. IsMinified(content) judges packed bundles by shape.
Custom types in YAML
Load extra project types from YAML — has_file, has_glob, has_subdir_glob, or a cel expression. Register your own stacks into the default registry.
CEL is opt-in
The base package has no CEL dependency. Add one blank import to enable cel: indicators — otherwise cel-go and its transitive deps stay out of your build.
coverage
Built-in project types.
28 types out of the box — languages, build tools, and static-site generators. 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
Recognised file languages: go · python · javascript · typescript · java · rust · c · cpp · csharp · kotlin · php · ruby · scala · r · matlab · perl · swift
usage
Two questions, two functions.
Detect the current directory's types, or walk a tree for every project root under it.
// What is *this* directory? for _, m := range projectdetect.Detect( os.DirFS("."), ".") { fmt.Printf("%s (via %s)\n", m.Type, m.Indicator) }
// Every project root under a tree. res, err := projectdetect.Find( ctx, "/path/to/code", projectdetect.FindOptions{}) if err != nil { log.Fatal(err) }
# Per-file language detection. projectdetect.LanguageForPath("src/app.py") // "python" projectdetect.LanguageForExt(".rs") // "rust" projectdetect.IsVendored("docs/js/jquery.min.js") // true
# Custom types in YAML. project_types: - name: my-stack indicators: - has_file: "my.config" - cel: '"services" in subdirs'
install
Add it to your module.
One dependency-light import. CEL support ships in a sub-package you enable only if you need it.
go get github.com/richardwooding/projectdetect
import "github.com/richardwooding/projectdetect"
import _ "github.com/richardwooding/projectdetect/celindicators"
Requires Go 1.26+. The CEL import is only needed for cel: indicators.