Versioneer
Blazing-fast dependency scanner & security audit tool for polyglot codebases
Zero config. Zero external dependencies. Instant results.
Scan 55,000 dependencies across 4,000+ projects in ~10 seconds — then sweep them for known vulnerabilities in one command.
See it in action
$ versioneer -resolve -check='axios@<1.6.0,lodash@<4.17.21' ~/
WARNING: 3 dependencies matched by name but version could not be resolved — marked UNRESOLVED.
FOUND 8 matching dependencies across rules.
── code/AgentGPT/next/package.json (1 deps) ──────────────────────────
NAME SPEC INSTALLED VIA ECO TYPE MANIFEST DEPS DIR
───── ─────── ───────── ──────── ─── ────── ──────── ────────
axios ^0.26.0 0.26.1 lockfile npm direct 1mo ago —
── code/swc/package.json (1 deps) ─────────────────────────────────────
NAME SPEC INSTALLED VIA ECO TYPE MANIFEST DEPS DIR
───── ─────── ───────── ──────── ─── ──── ──────── ────────
axios ^0.21.1 0.21.4 lockfile npm dev 9mo ago —
── code/legacy-app/package.json (1 deps) ──────────────────────────────
NAME SPEC INSTALLED VIA ECO TYPE MANIFEST DEPS DIR
────── ─────── ───────── ──── ─── ────── ──────── ────────
lodash 4.17.15 4.17.15 disk npm direct 6mo ago 3mo ago
...
8 dependencies across 4 projects (scanned in 1.23s)
Highlights
- 8 ecosystems — npm, Go, Python, Rust, Java, Ruby, PHP, Dart
- Lock file resolution —
package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lock, go.sum, Cargo.lock, plus on-disk and exec fallbacks
- Security sweep — match resolved versions against inline rules or a rules file; CI-friendly exit codes
- Pure Go, zero deps — stdlib only, single static binary
- Concurrent pipeline — parallel directory walking, streaming parsers, pipelined resolve
- 6 output formats — table, JSON, JSONL, CSV, Markdown, summary
Install
Go
go install github.com/justsml/versioneer/cmd/versioneer@latest
From source
git clone https://github.com/justsml/versioneer && cd versioneer
go build -o versioneer ./cmd/versioneer
Quick start
# Scan current directory
versioneer .
# Scan with actual installed versions + timestamps
versioneer -resolve ~/app
# Full JSON report
versioneer -resolve -format=json ~/app > report.json
Usage
Filtering
# Find every project that uses react
versioneer -dep=react ~/
# Only Python dependencies
versioneer -eco=python ~/
# Only dev dependencies
versioneer -type=dev ~/code
# Combine filters
versioneer -resolve -dep=axios -eco=npm -format=csv ~/code
Security sweeps
Check for known vulnerable or malicious packages — inline or from a rules file:
# Inline check (comma-separated rules)
versioneer -check='axios@<1.6.0,event-stream@=3.3.6,colors@>=1.4.1' ~/code
# From a rules file
versioneer -checkfile=vulns.txt ~/code
Exits with code 1 when matches are found (CI-friendly). Auto-enables version resolution.
Rules file format
One rule per line. # comments and blank lines are fine.
# package@constraint — ranges are comma-separated within a rule
axios@<1.6.0 # anything below 1.6.0
event-stream@=3.3.6 # exact malicious version
colors@>=1.4.1 # protest-ware versions
ua-parser-js@>=0.7.29,<0.7.31 # supply chain attack range
lodash@<4.17.21 # prototype pollution
@scope/pkg@>=2.0.0 # scoped packages work too
event-stream # name-only = any version
Version matching behavior:
- Matches against the resolved/installed version first (from lock files or
node_modules)
- Pinned specs (e.g.
1.7.9) are matched directly when no lock file is available
- Range expressions (e.g.
^1.3.5) without a resolved version are flagged as UNRESOLVED — never silently skipped or false-matched
Supported ecosystems
| Ecosystem |
Manifests |
Lock files / on-disk resolution |
| npm |
package.json |
package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lock, bun pm ls (binary lockb), node_modules/ |
| Go |
go.mod |
go.sum |
| Python |
requirements.txt, Pipfile, pyproject.toml |
.venv/, venv/ dist-info |
| Rust |
Cargo.toml |
Cargo.lock |
| Java |
pom.xml, build.gradle, build.gradle.kts |
— |
| Ruby |
Gemfile |
— |
| PHP |
composer.json |
— |
| Dart |
pubspec.yaml |
— |
| Format |
Flag |
Use case |
table |
-format=table |
Terminal (default) |
json |
-format=json |
Full structured report |
jsonl |
-format=jsonl |
Streaming / piping / log ingest |
csv |
-format=csv |
Spreadsheets, data pipelines |
markdown |
-format=markdown |
PRs, wikis, reports |
summary |
-format=summary |
Quick stats + staleness overview |
When -resolve is active, all formats include the resolved version, resolution source (lockfile/disk/exec), and timestamp columns.
Architecture
cmd/versioneer/main.go CLI entry point — flags, filtering, security checks
internal/
scanner/scanner.go Parallel directory walker + streaming project emitter
parser/ Per-ecosystem manifest parsers (8 ecosystems)
resolver/ Lock file + on-disk + exec version resolution
resolver.go npm, Go, Rust, Python, Bun resolvers + lock cache
timestamps.go Manifest, project dir, deps dir modified times
matcher/ Semver parsing + constraint matching
output/ Streaming formatters (table, json, jsonl, csv, md, summary)
model/dependency.go Core types: Dependency, Project, ScanResult
Design decisions
- Zero external dependencies — stdlib only, no cobra/viper/lipgloss
- 3-stage pipeline — directory walking, manifest parsing, and version resolution run as concurrent pipeline stages. When
-resolve is active, resolution begins while scanning is still discovering projects
- Parallel directory walker — goroutine-per-directory bounded by NumCPU semaphore, faster than
filepath.WalkDir on SSDs. Falls back to sequential walk when --gitignore is enabled
- Streaming lock file parsers — package-lock.json uses a streaming JSON token decoder (skips integrity hashes without allocating), yarn.lock uses a line-based state machine (13x faster than regex), Cargo.lock and go.sum use
bufio.Scanner
- Lock file caching —
sync.Map + sync.Once ensures monorepo lock files are parsed exactly once even across hundreds of sub-packages
- Resolution source tracking — every resolved version is tagged
lockfile, disk, or exec
- Bun support — parses
bun.lock JSONC, falls back to bun pm ls for binary bun.lockb, then to node_modules/
- Streaming output — formatters write directly to
io.Writer, no intermediate buffering
- Monorepo-aware — lock file lookups walk up to the repo root, stopping at
.git boundaries
Comparison
How does Versioneer compare to other tools?
| Tool |
License |
Commercial |
Ecosystems |
Built With |
| Versioneer |
MIT |
No |
8 |
Go (zero deps) |
| Snyk CLI |
Apache-2.0 |
Yes (freemium) |
10+ |
TypeScript |
| Socket CLI |
MIT |
Yes (freemium) |
3 |
TypeScript |
| Trivy |
Apache-2.0 |
Yes (Aqua) |
10+ |
Go |
| Grype |
Apache-2.0 |
Yes (Anchore) |
10+ |
Go |
| OSV-Scanner |
Apache-2.0 |
No |
12+ |
Go |
| Dependency-Check |
Apache-2.0 |
No |
7+ |
Java |
| Retire.js |
Apache-2.0 |
No |
1 |
JavaScript |
| safety |
MIT |
Yes (freemium) |
1 |
Python |
| audit.js |
Apache-2.0 |
Partial |
1 |
TypeScript |
Contributing
# Run tests
go test ./...
# Run benchmarks
go test -bench=. -benchmem ./internal/resolver/
# Build
go build ./cmd/versioneer
# Test a scan
go run ./cmd/versioneer -resolve -format=summary ~/your-code
License
MIT