npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

knip-delta

v0.1.1

Published

Diff two Knip JSON reports to show only the unused-code issues a change introduces or fixes — built for PR checks on codebases with an existing Knip backlog.

Downloads

361

Readme

knip-delta

Diff two Knip JSON reports and show only the issues a change introduced or resolved — not the entire existing backlog.

The problem

Knip finds unused files, exports, and dependencies in JS/TS projects, and it's genuinely good at it. But on any codebase that hasn't run Knip from day one, turning it on in CI means every PR — including one-line fixes — gets confronted with hundreds of pre-existing findings that have nothing to do with the change. That's enough friction that teams either never turn Knip on in CI, or turn it on and ignore it.

The existing Knip Reporter GitHub Action posts Knip's full report as a PR comment — every run, the complete list, no comparison against what already existed before the PR. knip-delta does the other half of the job: it diffs a base report against a head report and tells you what's actually new.

### ⚠️ Knip: 2 new issue(s) introduced by this PR

- `src/lib/pricing.ts`
  - **exports** `calculateLegacyDiscount`:42
  - **types** `UnusedPricingTier`:12

<details><summary>438 pre-existing issue(s), not introduced by this PR</summary>
...
</details>

What it is

  • A small CLI (knip-delta diff --base base.json --head head.json) that does the comparison and prints JSON, Markdown, or plain text.
  • A GitHub Action (action.yml) that wraps the CLI for CI use.
  • Not a fork or replacement of Knip. It only ever consumes knip --reporter json output — it has no opinion about how you configure Knip itself.

Install

npm install --save-dev knip-delta

Or use it without installing, via npx knip-delta.

CLI usage

# 1. Generate a report for your target branch
git checkout main
npx knip --reporter json > base.json

# 2. Generate a report for your PR branch
git checkout my-feature-branch
npx knip --reporter json > head.json

# 3. Diff them
npx knip-delta diff --base base.json --head head.json --format markdown

Options:

| Flag | Description | Default | | --- | --- | --- | | --base <path> | Knip JSON report for the base ref | required | | --head <path> | Knip JSON report for the head ref | required | | --format <fmt> | text, markdown, or json | text | | --out <path> | Write to a file instead of stdout | stdout | | --fail-on <mode> | added (exit 1 if new issues exist) or never | added |

GitHub Actions usage

Full example: .github/workflows/example-pr-check.yml. The gist — run Knip against both the base and head commit of the PR, then hand both JSON files to the action:

- uses: frontbond/knip-delta@v0
  id: knip-delta
  with:
    base-report: ${{ runner.temp }}/base.json
    head-report: ${{ runner.temp }}/head.json

- uses: peter-evans/create-or-update-comment@v4
  with:
    issue-number: ${{ github.event.pull_request.number }}
    comment-tag: knip-delta
    edit-mode: replace
    body-path: ${{ steps.knip-delta.outputs.markdown-path }}

The action fails the step when new issues were introduced (fail-on: added, the default) and always produces markdown-path / json-path outputs, so you can post a comment even when the step fails (if: always() on the comment step, as in the example workflow).

Why two checkouts?

knip-delta only diffs two already-generated reports; it deliberately has no opinion about how you produce them. The example workflow's "checkout base, npm ci, run knip; checkout head, npm ci, run knip" is the same pattern used by tools like size-limit and bundlewatch — it's slower than a single checkout, but it means installed dependencies match the code actually being analyzed on each side, even if a PR changes package.json itself.

Programmatic use

import { computeDiff, toMarkdown } from "knip-delta";

const diff = computeDiff(baseReport, headReport);
console.log(diff.totals); // { added: 2, removed: 0, unchanged: 438 }
console.log(toMarkdown(diff));

How issues are matched

An issue is identified by (file path, category, name) — deliberately excluding line/column/position. Those shift whenever unrelated code above an issue changes, which would otherwise make an untouched issue look "new" just because the base and head checkouts diverge elsewhere in the file.

One consequence: if a PR renames a file or moves an export to a new file, knip-delta reports it as one resolved issue + one new issue, rather than recognizing it as a move. Good enough for the common case; a smarter same-file-content heuristic is a reasonable future improvement.

Development

npm ci
npm run build   # tsc -> dist/
npm test        # vitest, against real `knip --reporter json` fixtures

dist/ is committed (not gitignored) because this repo is consumed directly as a GitHub Action via uses: owner/knip-delta@version — there's no build step at consumption time. CI fails if dist/ drifts from src/.

License

MIT