Safeguard
Industry Analysis

How snyk-to-html converts CLI scan results into shareable...

A technical look at how snyk-to-html converts Snyk CLI JSON scan output into shareable, self-contained HTML reports for CI pipelines and audits.

Aman Khan
AppSec Engineer
Updated 8 min read

Running snyk test --json produces exactly what a machine wants: a dense, deeply nested JSON blob listing every vulnerable dependency, its CVE identifiers, severity scores, and dependency paths. It is exactly what a human does not want to read in a terminal. For teams that need to hand a scan result to a compliance auditor, attach it to a pull request, or archive it as evidence for a SOC 2 review, raw JSON is a dead end. That gap is why Snyk maintains snyk-to-html, an open-source Node.js package published on npm that converts Snyk CLI JSON output into a self-contained, readable HTML report. It takes the same snyk test --json payload the CLI already produces and renders it as a formatted page with severity grouping, vulnerability tables, and remediation guidance — no dashboard login required. Here is how the conversion actually works, and where a static HTML file stops being enough.

What problem does snyk-to-html actually solve?

The core problem is that Snyk CLI's native output formats are built for two different audiences, and neither is "a person skimming a report." The default human-readable CLI output is a scrolling wall of text in a terminal, fine for a single local scan but unusable once you have hundreds of findings. The --json flag solves machine-readability for CI pipelines that need to parse results programmatically, but it is not something you attach to an email or a ticket. snyk-to-html fills the gap between those two: it consumes the same structured JSON and produces a static .html file that opens in any browser, requires no server, and can be stored as a build artifact, emailed to a stakeholder, or archived alongside audit documentation. This is why it shows up so often in CI/CD pipelines — teams already generate the JSON as part of automated scanning, and turning it into HTML is a near-zero-cost addition to that same job.

How does snyk-to-html transform JSON into HTML?

It works as a templating layer, not a re-scanner — snyk-to-html never talks to Snyk's API or re-evaluates any dependency; it only reformats data that already exists. The published tool takes a JSON file (or a JSON stream piped into it) and runs it through an HTML templating engine (the project's public repository ships Handlebars template files, with .hbs templates defining the report layout) to produce the final markup. The default template walks the same structure Snyk's CLI JSON already exposes — vulnerabilities, grouped by package and severity — and renders it into a table with columns for severity level, package name and version, vulnerability title, CVE/CWE identifiers, introduced-through dependency path, and a remediation/upgrade suggestion where one exists. Because the transformation is template-driven rather than hardcoded, the same underlying data can be rendered differently depending on which template file is supplied, which is also what makes the tool extensible.

How do you actually run it in a pipeline?

Before any of this works you need to install snyk cli — npm install -g snyk — and authenticate it against your Snyk account. The most common pattern from there is a two-step shell command: run the snyk test cli command with JSON output, then pipe or feed that output into the converter. In practice that looks like:

snyk test --json > results.json
snyk-to-html -i results.json -o report.html

or, piped directly without an intermediate file:

snyk test --json | snyk-to-html -o report.html

Documented command-line options include -i/--input to specify a JSON input file, -o/--output to name the resulting HTML file, -t/--template to point at a custom Handlebars template instead of the default, and an array-handling option for multi-project scans (where snyk test returns a JSON array rather than a single object, such as when scanning a monorepo with several manifest files). Teams typically wire this into a CI job — GitHub Actions, GitLab CI, Jenkins — so that every pipeline run that executes a Snyk scan also emits an HTML artifact, which is then uploaded as a build artifact or attached to a release for later review. Because the HTML file is fully self-contained, it doesn't require network access or authentication to view later, which matters when an auditor wants to look at a scan result from a build that ran six months ago.

What can you customize in the generated report?

The main lever is the template file itself, since snyk-to-html explicitly supports supplying a custom template via the -t flag instead of using the bundled default. Organizations that want a report matching internal branding, a specific column layout, or a reduced view showing only high/critical findings can write their own Handlebars template and point the tool at it rather than accepting the stock output. This is meaningful for compliance-oriented use cases: a security team preparing evidence for a SOC 2 Type II audit or an internal risk review often doesn't want every low-severity finding cluttering the document, so a trimmed custom template that filters or highlights by severity threshold is a common adjustment. Because the tool is open source, the template files are inspectable and forkable, which is also how several downstream integrations and CI marketplace actions that "wrap" snyk-to-html have built severity-filtered or summary-only variants on top of the base project.

What does snyk-to-html not do?

It does not aggregate results across scans, track remediation over time, or connect to any live vulnerability feed — each HTML file is a snapshot of a single JSON input, generated once and then static. If a dependency gets patched next week, the report you generated today does not update; you have to re-run the scan and regenerate the file. It also does not merge results from multiple tools — if a pipeline runs Snyk alongside a container scanner, a secrets scanner, and an IaC checker, snyk-to-html only knows about the Snyk JSON it was given, so the resulting report reflects one tool's view of risk, not the full picture across a software supply chain. And because the output is a flat HTML file rather than a queryable dataset, there's no built-in way to filter, search across many historical reports, or correlate a finding back to which commit or team introduced it, beyond what's visible in a single file at a time.

Why do teams still reach for a static HTML report in 2026?

Because the audience for a vulnerability report is frequently not the same audience that runs the scanner, and a static file is the lowest-friction way to hand off results without provisioning dashboard access. A security engineer reviewing findings in a live tool is a different use case from a compliance auditor who needs a point-in-time artifact, or an engineering manager who wants a readable summary attached to a Jira ticket without logging into anything. Static HTML also survives outside the tool's own infrastructure — it can be archived in a document management system, attached to a vendor security questionnaire response, or stored as evidence for exactly the timeframe an audit period covers. That durability, combined with the fact that generating it costs one extra CLI command in an already-scripted pipeline, is why the pattern has persisted even as most vendors, including Snyk, have also built out live web dashboards.

How Safeguard Helps

Point-in-time HTML exports are useful for handing a single scan result to a single reviewer, but they don't hold up as the only evidence layer once an organization is running multiple scanners across multiple repositories and needs to show continuous, not snapshot, compliance. Safeguard is built around that continuity gap: instead of a static file generated per scan, Safeguard aggregates findings across your software supply chain — SCA, container, IaC, and secrets scanning — into a single normalized view, tied to SBOM data and provenance attestations rather than a one-off JSON export. That means a finding isn't just "here's what this report showed on this date," it's tracked against the artifact, the commit, and the deployment that carried it, so remediation status stays current instead of frozen in an HTML file the moment it's generated.

For teams that need audit-ready evidence — SOC 2, ISO 27001, or customer security questionnaires — Safeguard produces reporting that's already structured for that purpose: filterable by severity and control mapping, exportable on demand, and backed by a live data model rather than a template rendered once from a single tool's output. If your current workflow is stitching together snyk-to-html exports from several pipelines to assemble a compliance picture, that's usually a sign the underlying need has outgrown per-scan HTML files and is ready for a supply-chain-wide reporting layer instead.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.