Large repositories rarely have a single, tidy dependency manifest. A mid-size monorepo can easily contain a package.json for the frontend, three or four pom.xml files for internal Java services, a requirements.txt for a data pipeline, and a go.mod tucked inside a tools directory nobody remembers writing. Snyk's --all-projects flag exists specifically to handle that mess: instead of requiring an engineer to point the CLI at each manifest individually, it walks the codebase and tries to find every dependency file it recognizes in one pass. That sounds simple, but the mechanics of "find every manifest" — how deep the walk goes, what gets skipped, and what counts as a duplicate — determine whether a supply chain scan is actually complete or just looks complete. This post walks through the publicly documented behavior of the flag: how discovery works, where its boundaries are, and why those boundaries matter once a repository crosses a few hundred subdirectories.
What does --all-projects actually change about a scan?
It replaces manual, per-manifest invocation with a single recursive scan of the working directory. Without the flag, snyk test looks at the current directory and expects you to tell it (or have it infer from context) which single project manifest to evaluate — one package.json, one pom.xml, one Gemfile. With --all-projects, the CLI instead traverses the directory tree from the path you give it, applies its ecosystem-specific detection logic at each directory it visits, and builds a list of every manifest that matches a supported package manager. Each matched manifest is then treated as its own project and tested independently, so a single snyk test --all-projects invocation against a monorepo root can produce dozens of separate dependency graphs and vulnerability reports in one run rather than dozens of separate commands.
How does the CLI decide which files count as a manifest?
It matches file names and extensions against a fixed list of patterns tied to each supported package manager. package.json plus a lockfile signals npm or Yarn; requirements.txt, Pipfile, or poetry.lock signal Python; pom.xml or build.gradle/build.gradle.kts signal Java or Kotlin builds via Maven or Gradle; Gemfile signals Ruby; go.mod signals Go modules; composer.json signals PHP; .csproj and packages.config cover .NET. This is pattern-based detection, not semantic analysis of the file's contents beyond confirming it parses as a manifest for that ecosystem — the CLI isn't inferring "this project uses Python" from import statements, it's recognizing a known filename and handing it to the matching language plugin. That matters because any dependency declared through a mechanism the CLI doesn't recognize by filename — a custom internal build tool, a vendored dependency list embedded in a non-standard file, a manifest format the CLI's plugin set hasn't been updated to support yet — simply won't surface as a project, regardless of how central it is to the repository.
How far into the directory tree does the scan actually reach?
By default it does not recurse without limit — Snyk documents a configurable maximum directory depth for --all-projects, controlled by the --detection-depth flag, and the CLI's own guidance is explicit that very large repositories should tune this value rather than assume the default reaches everything. In practice this means the scan behaves like a bounded breadth walk from the root path you supply: it looks a fixed number of directory levels down, checking each level for manifest patterns, and stops descending once that limit is hit. For a small repository with a flat structure this is invisible — every manifest sits well within range. For a large monorepo with deeply nested service directories, generated build output folders, or a packages/team-a/service-b/src style layout, a manifest sitting six or seven levels down can fall outside the default scan boundary entirely and never get tested, with no error raised to indicate it was skipped.
What gets excluded automatically, and why does that matter?
Common non-source directories are filtered out of the walk so the CLI doesn't waste time — and inflate results — by treating installed dependency trees as separate projects. The clearest example is node_modules: a nested package.json inside an installed npm dependency is not itself a project you own, so --all-projects is built to avoid re-discovering and re-testing every transitive package as though it were a first-party manifest. Snyk exposes an --exclude flag precisely because teams need to extend this filtering to their own build artifacts, vendored third-party code, or generated directories that would otherwise produce noisy or misleading results. The trade-off is the same one every allowlist/denylist mechanism has: exclusion rules that are too narrow let dependency-installation directories pollute the project list, while exclusion patterns that are too broad — or copy-pasted from another repository's .snyk config without review — can silently remove a directory that actually contains a legitimate, first-party manifest.
How does Snyk handle manifests that overlap or duplicate each other?
It provides explicit tooling to collapse redundant detections rather than assuming discovery alone produces a clean result set. In ecosystems like npm, a monorepo managed with workspaces can produce lockfiles that repeat large portions of the same dependency tree across multiple package.json files, and scanning each one independently would report the same underlying vulnerability many times over under different project names. Snyk's CLI includes options such as --prune-repeated-subdependencies to reduce this duplication in the resulting graphs. The existence of that flag is itself informative: it confirms that raw manifest discovery under --all-projects is a first pass, not a fully deduplicated inventory, and that getting a clean, non-redundant view of a large repository's dependencies requires deliberately combining discovery with pruning and exclusion options rather than relying on defaults.
What actually goes wrong when this is run against a genuinely large repository?
The most common failure mode is silent under-coverage rather than an outright error. Because directory depth limits, default exclusions, and filename-pattern matching all work quietly in the background, a scan can complete successfully, report zero critical findings, and still have never reached a manifest that exists 20 levels deep in a service directory, or a dependency file whose format the installed CLI plugin doesn't recognize because the manifest is templated or generated at build time. Teams running --all-projects against sprawling monorepos need to actively verify the discovered-project count against their own knowledge of how many services and manifests actually exist — comparing the CLI's project list to a repository inventory maintained independently — rather than treating a clean scan result as proof that every manifest was evaluated. At the scale of hundreds of services, thousands of directories, and manifests added continuously by dozens of teams, that verification step is easy to skip and expensive to skip wrongly.
How Safeguard Helps
Manifest discovery is a foundational problem for any supply chain security tool, not just Snyk's — and the same structural challenges apply broadly: depth limits, filename-pattern matching, and exclusion rules all trade completeness for performance, which means point-in-time CLI scans need something to check their coverage against. Safeguard approaches this by maintaining a continuously updated inventory of repositories, manifests, and build artifacts across an organization's software supply chain, independent of any single scanner's traversal limits or default exclusion lists. Rather than relying on a single recursive walk executed at scan time, Safeguard correlates what a repository actually contains — including manifests that may sit deep in a directory tree, live inside less common build tooling, or get added between scheduled scans — against what security tooling reports finding, surfacing gaps where coverage assumptions and repository reality diverge. For teams running Snyk, Trivy, or any other manifest-based scanner across large monorepos, that independent inventory layer is what turns "the scan finished clean" into a verified, auditable claim about what was actually evaluated.