Functional Difference Between OSV-Scanner's --recursive and --no-ignore Flags

The --recursive flag enables deep directory traversal to discover lockfiles and SBOMs in nested subdirectories, while --no-ignore disables .gitignore pattern matching to force inclusion of excluded files in vulnerability scans.

OSV-Scanner, Google's open-source vulnerability scanner for project dependencies, exposes two CLI flags that frequently cause confusion due to their similar "expand the scan" behavior. While both --recursive (or -r) and --no-ignore increase analysis coverage, they operate on orthogonal dimensions of the scanning pipeline. Understanding the functional difference between osv-scanner's --recursive and --no-ignore flags ensures you correctly configure security audits for monorepos, generated artifacts, and vendored dependencies.

How --recursive Controls Directory Traversal

The --recursive flag determines search depth when the scanner indexes supported manifests, lockfiles, and SBOM documents within the provided paths.

By default, OSV-Scanner examines only the top-level directory and its immediate children for supported files. When you pass --recursive, the scanner descends into all subdirectories recursively, identifying vulnerable dependencies across your entire project tree, including deeply nested packages.

Implementation in scan.go

According to the google/osv-scanner source code, the flag is defined in [cmd/osv-scanner/scan/source/command.go](https://github.com/google/osv-scanner/blob/main/cmd/osv-scanner/scan/source/command.go) (lines 44‑55) and stored in the ScannerActions.Recursive field within [pkg/osvscanner/osvscanner.go](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/osvscanner.go) (line 45).

The actual directory traversal logic resides in [pkg/osvscanner/scan.go](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/scan.go). The pathToRootMap function (lines 323‑337) adds directories as targets only when !recursive constraints are satisfied, determining whether to treat nested paths as separate scan roots. Additionally, the scanner passes IgnoreSubDirs: !actions.Recursive to the Scalibr extraction engine (lines 360‑363), effectively controlling whether the underlying engine descends into subdirectories.

The helper function isDescendent (lines 352‑383) also consults this flag to distinguish between direct children and deeper descendants when building the file discovery map during the scan initialization phase.

How --no-ignore Controls File Exclusion

The --no-ignore flag controls file eligibility by disabling automatic respect for .gitignore exclusion patterns.

By default, OSV-Scanner leverages the Scalibr library to automatically skip files and directories listed in .gitignore files, matching Git's standard exclusion behavior. When you specify --no-ignore, the scanner treats every file on disk as eligible for analysis, regardless of ignore rules, effectively scanning vendored dependencies, build artifacts, and temporary files.

Gitignore Integration Mechanism

Like --recursive, this flag is registered in [cmd/osv-scanner/scan/source/command.go](https://github.com/google/osv-scanner/blob/main/cmd/osv-scanner/scan/source/command.go) (lines 51‑55) and stored as ScannerActions.NoIgnore in [pkg/osvscanner/osvscanner.go](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/osvscanner.go) (line 47).

The critical inversion happens in [pkg/osvscanner/scan.go](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/scan.go) (lines 240‑242) when configuring the Scalibr scan:

Config: scalibr.ScanConfig{
    UseGitignore: !actions.NoIgnore,
    // ...
}

When UseGitignore is true (the default), Scalibr consults .gitignore files during the file walking phase. When --no-ignore is passed, UseGitignore becomes false, forcing the extraction engine to analyze all encountered files including those in node_modules/, vendor/, or other ignored paths.

Functional Comparison

These flags target different stages of the scanning pipeline and can be used independently or combined:

  • --recursive: Expands the geographic scope of the scan to nested directories. It answers "where should I look?" by controlling directory traversal depth through IgnoreSubDirs and pathToRootMap logic.
  • --no-ignore: Expands the candidate set of files within the searched locations. It answers "which files are valid targets?" by inverting the UseGitignore Scalibr configuration.

Use --recursive when you have nested projects or monorepos with dependencies defined in subdirectories. Use --no-ignore when you need to audit vendored code or generated lockfiles that reside in git-excluded directories like dist/ or build/.

Practical Command Examples

Configure your vulnerability scans based on whether you need deeper directory traversal, inclusion of ignored files, or both.

Scan only the top-level directory while respecting .gitignore (default behavior):

osv-scanner scan source ./my-project

Scan all subdirectories recursively, but skip files listed in .gitignore:

osv-scanner scan source -r ./my-project

Scan the entire repository including vendored dependencies and build artifacts:

osv-scanner scan source -r --no-ignore ./my-project

Scan a specific lockfile without recursion while still applying ignore rules:

osv-scanner scan source --lockfile=go.mod ./my-project

Summary

  • --recursive: Enables deep directory traversal via ScannerActions.Recursive, implemented in pathToRootMap and isDescendent functions in scan.go, and passed to Scalibr as IgnoreSubDirs: !recursive.
  • --no-ignore: Disables .gitignore filtering by setting ScannerActions.NoIgnore to true, which inverts to UseGitignore: false in the Scalibr configuration.
  • Orthogonal operation: These flags operate independently—--recursive controls search depth while --no-ignore controls file eligibility.
  • Combined usage: Use -r --no-ignore together to perform comprehensive security audits of entire repository trees including normally excluded vendored paths.

Frequently Asked Questions

Can I use --recursive and --no-ignore together?

Yes. Combining osv-scanner scan source -r --no-ignore ./project performs a recursive scan of all directories while overriding .gitignore exclusions. This configuration is essential for security audits of vendored dependencies or generated lockfiles that typically reside in ignored directories such as node_modules/ or vendor/.

Does --no-ignore affect scan performance?

Yes. Scanning with --no-ignore can significantly increase execution time and memory consumption because the scanner processes files normally excluded by Git, including build artifacts, cache directories, and third-party vendored code containing thousands of files. Only enable this flag when you suspect vulnerable dependencies exist in ignored paths.

Where is the recursive directory logic implemented?

The recursive traversal logic resides primarily in [pkg/osvscanner/scan.go](https://github.com/google/osv-scanner/blob/main/pkg/osvscanner/scan.go) within the pathToRootMap function (lines 323‑337) and the isDescendent helper (lines 352‑383). These functions determine whether to treat nested directories as separate scan roots and control the IgnoreSubDirs parameter passed to the Scalibr extraction engine.

Why does osv-scanner respect .gitignore by default?

The default behavior aligns with developer intent—files listed in .gitignore are typically build outputs, temporary files, or vendored dependencies that developers do not consider part of their editable source code. However, since security vulnerabilities in vendored dependencies still affect your application, the --no-ignore flag exists as an opt-in override to ensure comprehensive vulnerability detection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →