Skip to content

Output format

Two formats: a human-readable text report (default) and machine-readable JSON (--json). Both emit one logical entry per target. If you parse the output programmatically (CI gate, dashboard, AI agent), prefer --json — the text format is stable but optimized for reading.

All results — text and --json — are written to stdout. Progress and diagnostics go to stderr, so a redirect like dependency-audit . > result.json captures only the result. While auditing, a one-line version banner (dependency-audit vX.Y.Z) followed by a live progress line (current phase, deps materialized) is drawn on stderr, but only when stderr is an interactive terminal — under a pipe, a file, or CI it is silent, leaving stderr empty on a clean run. (For a machine-readable record of the producing version, read the version field of the --json envelope below.)

The report is a sequence of per-target blocks, then a summary line. Each line is prefixed with two spaces and a status symbol:

SymbolMeaning
The target is clean — no findings and no notices.
A finding (a real problem that fails the audit).
A notice (a coverage gap — no/unreachable type surface; does not fail).
An ignored finding (suppressed by a rule; does not fail). Ends with — ignored.
?An unchecked specifier (dynamic/opaque — surfaced, not resolved).
A skipped target — a non-package path (does not affect the exit code).
An error — the target could not be audited at all.
A remediation suggestion (continuation of the preceding / line).
A root-cause note: the finding is caused by another target audited in the run — a continuation under a finding, or (with --collapse-root-cause) a muted, non-failing finding row.

When stdout is a color-capable terminal, severity is also carried by color — red for findings/errors, yellow for notices/unchecked, green for clean, and muted (dim) for ignored/skipped/secondary detail. Color is auto-disabled when the output isn’t a TTY (e.g. piped to a file or another program), with one exception: under GitHub Actions (GITHUB_ACTIONS=true) color is emitted anyway, since its log viewer renders ANSI even though the step’s stdout is a pipe. NO_COLOR and FORCE_COLOR are honored throughout and override that exception. The symbols above are the source of truth; color is purely a visual aid (and never emitted under --json), so parsers should key on the symbols, not the color.

<packageName>@<version> <target>
[resolved: <tarball-url>] # only for a fetched spec/URL
[integrity: <sri>] # only for a fetched spec/URL
<one or more status lines, in this order:>
✓ no undeclared imports # only when fully clean
ℹ <surface> <message> # notices
✗ <surface> [<kind>] <specifier> (<file>) # findings
→ <suggestion>
↳ caused by <producer-target> (<notice>) … # only when correlated to a producer in the run
↳ <surface> [<kind>] <specifier> (<file>) — root cause: <producer> (<notice>) # only under --collapse-root-cause
– <surface> [<kind>] <specifier> (<file>) — ignored # ignored findings
? unchecked <specifier> (<reason>; <file>) # unchecked specifiers
  • <packageName> falls back to the target string if the manifest has no name; @<version> is omitted if the manifest has no version.
  • <surface> is types or runtime; <kind> is a finding kind; <specifier> is the full bare specifier as written (e.g. react/jsx-runtime), not just the owning package; <file> is the package-relative path where it was first seen.
  • Columns are space-padded for alignment; treat runs of whitespace as a single separator when parsing.
<target>
⚠ error <message> # could not be audited
<target>
↷ skipped <reason> # a non-package path (neutral)

When the run has at least one failing finding, a consolidated recap is printed just above the summary line, so the actual problems sit at the foot of a long log (e.g. a CI run) instead of buried in the per-target blocks. Each row names its owning package, so it reads standalone; collapsed findings (under --collapse-root-cause) are omitted, since they don’t fail the run. The recap is omitted entirely on a clean run.

Findings:
✗ <packageName> <surface> [<kind>] <specifier> (<file>)
<N> package[s], <F> finding[s][, <K> collapsed][, <G> ignored][, <C> notice[s]][, <S> skipped][, <E> error[s]].

The collapsed, ignored, notice, skipped, and error clauses appear only when their count is non-zero. <F> counts findings that fail the run — non-ignored, and (under --collapse-root-cause) non-collapsed.

A { tool, version, results } envelope. tool is always "dependency-audit" and version is the producing CLI version — recorded so a saved audit artifact stays reproducible as the resolution behavior evolves. results is a JSON array with one element per target, in input order; each element is an AuditResult, an error entry (could not audit), or a skip entry (a non-package path).

{
"tool": "dependency-audit",
"version": "0.2.1", // the producing CLI version
"results": [
/* one AuditResult / error entry / skip entry per target */
],
}
{ "target": "<target>", "error": "<message>" }
{ "target": "<target>", "skipped": "<reason>" }

Distinguish the three by key: an error key → could not audit (exit 2); a skipped key → a neutral non-package path; otherwise it is an AuditResult (use ok).

{
"target": "./packages/my-lib", // the target as passed in
"source": {
// how it was acquired
"kind": "directory", // "directory" | "tarball" | "spec"
"resolved": {
// present only for a fetched spec/URL
"name": "my-lib",
"version": "1.2.3",
"tarball": "https://registry.npmjs.org/my-lib/-/my-lib-1.2.3.tgz",
"integrity": "sha512-…",
},
},
"packageName": "my-lib", // string | undefined (from the manifest)
"packageVersion": "1.2.3", // string | undefined
"ok": false, // true when findings is empty (notices do not affect ok)
"findings": [
{
"specifier": "react", // the bare specifier as written
"packageName": "react", // the normalized owning package
"surface": "types", // "types" | "runtime"
"kind": "undeclared", // see Findings & notices
// "reason": "condition-mismatch", // only on some `unresolved` runtime findings
// "causedBy": { "target": "./packages/producer", "packageName": "@scope/producer", "notice": "types-unreachable" }, // only when correlated to a producer in the run
// "leakedVia": ["some-dep"], // declared dep(s) that also expose this type (likely leaked in; types `undeclared` finding)
"firstSeenIn": "dist/index.d.ts", // package-relative path
"suggestion": "declare \"@types/react\"",
},
],
"ignored": [
/* Finding[] suppressed by an ignore rule, same shape */
],
"usedIgnoreRules": [
{ "package": "optional-plugin" }, // the run's ignore rules that suppressed something in this target
],
"unchecked": [
{ "specifier": "", "reason": "dynamic specifier", "firstSeenIn": "dist/index.js" },
],
"notices": [{ "kind": "types-not-built", "surface": "types", "message": "" }],
"resolvedDeps": [
{ "name": "react", "range": "^18.0.0", "version": "18.3.1" }, // version: string | undefined if it could not be materialized
],
}
FieldTypeNotes
targetstringThe target as passed on the CLI / to audit().
source.kind"directory" | "tarball" | "spec"How the target was acquired.
source.resolvedobject | absentPresent only for a fetched spec/URL; records the moving target’s identity + SRI.
packageNamestring | undefinedFrom the target manifest.
packageVersionstring | undefinedFrom the target manifest.
okbooleantruefindings is empty. Notices and unchecked do not affect ok.
findingsFinding[]Non-ignored problems. See Findings.
ignoredFinding[]Findings suppressed by a rule, echoed for auditability.
usedIgnoreRulesIgnoreRule[]The ignore rules that suppressed at least one finding in this target — a rule unused across every target of a run is stale (the CLI warns; see Stale ignore rules).
uncheckedUncheckedSpecifier[]Dynamic/opaque specifiers static analysis could not resolve.
noticesNotice[]Coverage gaps. See Notices.
resolvedDepsResolvedDependency[]Every declared dep and the version materialized (undefined if it could not be fetched/linked).

Iterate payload.results (each entry below is one of its elements); read payload.version if you need the producing tool version.

  • Pass/fail per target: entry.error !== undefined → could not audit; entry.skipped !== undefined → a non-package path (neutral, ignore for pass/fail); else entry.ok → pass/fail on findings.
  • Coverage: count entry.notices to report “audited N, M with no analyzable type surface”. Treat as failure only if you opt into --require-types (CLI) or check notices.length yourself (API).
  • Aggregate exit semantics mirror the CLI: any error entry → 2; else any ok === false → 1; else 0. Skip entries are neutral. (--collapse-root-cause is a CLI-only exit/presentation flag — it does not change entry.ok, so under it the CLI can exit 0 while an entry.ok is false; a JSON consumer that wants the same behavior treats a finding with causedBy as non-failing itself.)