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

gqlprune

v2.10.0

Published

This script helps identify unused GraphQL operations (queries, mutations, subscriptions) in your project. It scans .gql files for operations and checks if they are being used in your TypeScript/JavaScript files.

Readme

gqlPrune: GraphQL Unused Operations Checker

npm npm downloads node License: MIT

CI codecov Socket Badge OpenSSF Scorecard OpenSSF Best Practices

gqlPrune is a utility that identifies unused GraphQL operations (queries, mutations, subscriptions) and unused fragments in your project. It scans .gql/.graphql files and checks whether each operation is referenced in your TypeScript/JavaScript source, and whether each fragment is spread by an operation or referenced in source — all without needing a running server or schema.

Migrating from 1.x to 2.0

  • Node.js ≥ 20 is now required.
  • The CLI command is gqlprune (lowercase), matching the package name — npx gqlprune and a global gqlprune both work.
  • Usage detection is broader and configurable. It now also matches lazy/suspense hooks and the generated <Name>Document constant, not just use<Name><Type>. If you use a different client (urql, react-query, raw documents, …), set usagePatterns so your operations aren't reported as unused.
  • Folder exclusion now works as documented. excludedFolders matches by folder name or root-relative path, and node_modules/.git are always excluded. (In 1.x the documented node_modules entry silently did nothing.)

How it detects usage

An operation is considered used if any of a set of search strings derived from its name appears in your source files. By default gqlPrune looks for the conventions emitted by GraphQL Code Generator (the typescript-react-apollo / near-operation-file presets):

For an operation query GetUser, the defaults match:

| Pattern | Example | | ------------------------ | ------------------------ | | use{Name}{Type} | useGetUserQuery | | use{Name}Lazy{Type} | useGetUserLazyQuery | | use{Name}Suspense{Type}| useGetUserSuspenseQuery| | {Name}Document | GetUserDocument |

If your project uses a different convention (urql, react-query, graphql-request, Vue, raw documents, etc.), override the patterns via usagePatterns in the config — see below. Without that, operations may be incorrectly reported as unused.

Unused fragments

gqlPrune also reports fragments that are never used, across files and without a schema. A fragment is considered used when it is either:

  • spread (directly or transitively) by any operation in your .gql corpus, or
  • referenced in your source via a fragment pattern — by default the codegen <Name>FragmentDoc constant (e.g. under fragment masking). Override with fragmentUsagePatterns.

A fragment spread only by another unused fragment is reported too. Note: a fragment is kept alive by any operation that spreads it, even an unused one — that operation is reported separately, so the fragment surfaces on the next run once you remove the operation.

Avoiding false "all clear" results

Because usage is detected by string-matching srcDir, GraphQL Code Generator output that lives inside srcDir is a trap: a single generated file (e.g. src/gql/graphql.ts) references every operation, so everything looks used and nothing is ever reported unused — silently.

gqlPrune guards against this. When one source file alone references most of your operations, it prints a warning naming the file and pointing you at exclude:

⚠ Suspected generated file "src/gql/graphql.ts" references 100% of all operations (50/50) and looks generated — add it to "exclude" in gqlPrune.config.yaml or unused results will be unreliable.

Add it to exclude (e.g. '**/*.generated.ts') and re-run — or just run gqlprune init, which detects such a file and pre-fills it into exclude for you. The warning goes to stderr (so it also surfaces in --json mode) and is included in the JSON report's warnings array; it does not change the exit code.

Setup

Installation

Requires Node.js ≥ 20.

npm install --save-dev gqlprune

Configuration

Run the init command to launch a configurator that generates gqlPrune.config.yaml at the root of your project. It auto-detects your GraphQL and source directories (scanning the project, excluding node_modules/.git/dist) and offers them as defaults you can accept or override. It also detects a generated file that would mask your results (the false "all clear" trap) and pre-fills it into exclude, so your first run is truthful. After writing the file it prints a quick preview of what a real run would find:

npx gqlprune init
✓ Found 42 operations in 12 files; 5 look unused. Run "gqlprune" to see them.
graphqlDir: ./path/to/graphql
srcDir: ./src
# Files/folders to skip (gitignore-flavored globs). `init` pre-fills any
# generated file it detects (it would otherwise mask all results); add more.
exclude:
  - src/gql/graphql.ts
  - '**/__generated__'
# Optional — override how operation usage is detected.
# Supports {name}, {Name}, {type}, {Type} placeholders.
usagePatterns:
  - use{Name}{Type}
  - '{Name}Document'
# Optional — override how fragments are matched in source (e.g. masking).
# Supports {name}, {Name} placeholders.
fragmentUsagePatterns:
  - '{Name}FragmentDoc'
  • graphqlDir: directory — or an array of directories — containing your .gql/.graphql files.
  • srcDir: directory — or an array of directories — containing your source files (.ts, .tsx, .js, .jsx).
  • exclude (optional): gitignore-flavored glob patterns for files and folders to skip. A name without a slash matches anywhere by basename (__generated__), a path with a slash is anchored to the project root (src/legacy), ** matches any depth, *.generated.ts matches files, and a leading ! re-includes. A ! re-include always wins (order-independent), but — as in gitignore — it can't re-include a path whose parent directory is excluded (excluded directories aren't traversed). node_modules and .git are always excluded.
  • excludedFolders (optional, deprecated — use exclude): folder names or root-relative paths. Still honored and merged into the same matcher.
  • usagePatterns (optional): templates used to detect operation usage. Defaults to the table above when omitted.
  • fragmentUsagePatterns (optional): templates for detecting fragments referenced directly in source (fragment masking). Defaults to {Name}FragmentDoc.

For monorepos or projects with scattered operations, graphqlDir and srcDir accept a list of directories:

graphqlDir:
  - ./packages/web/graphql
  - ./packages/admin/graphql
srcDir:
  - ./packages/web/src
  - ./packages/admin/src

Without a config file (CLI flags)

Every config field has a matching flag, so you can run gqlPrune with no gqlPrune.config.yaml — handy for a one-off npx try with zero setup:

npx gqlprune --graphql ./graphql --src ./src --ignore __generated__

| Flag | Config field | | ---- | ------------ | | --graphql <dir> | graphqlDir | | --src <dir> | srcDir | | --ignore <folder> (repeatable) | excludedFolders | | --pattern <template> (repeatable) | usagePatterns | | --fragment-pattern <template> (repeatable) | fragmentUsagePatterns |

Both --flag value and --flag=value work, in any order. Precedence: a flag overrides the same field in the YAML; flags alone work with no YAML; YAML alone works exactly as before. A list flag (e.g. --ignore) replaces that list from the YAML rather than appending to it.

Usage

npx gqlprune

This prints any unused GraphQL operations and fragments. The command exits with:

  • 0 when nothing unused is found (suitable for CI gates).
  • 1 when unused operations or fragments are found (or on configuration errors).

Print the installed version with gqlprune --version (or -v).

JSON output

Pass --json for a machine-readable report (CI, dashboards, scripting) instead of the human-readable tables:

npx gqlprune --json
{
  "unusedOperations": [
    { "name": "GetUser", "type": "query", "file": "graphql/user.gql", "line": 1 }
  ],
  "unusedFragments": [
    { "name": "UserFields", "file": "graphql/user.gql", "line": 8 }
  ],
  "warnings": [],
  "summary": { "unusedOperations": 1, "unusedFragments": 1 }
}

Only the JSON is written to stdout and the exit code is unchanged (0 clean / 1 unused), so it pipes cleanly into jq and CI gates. The warnings array carries advisory messages — currently a heads-up when a generated file may be masking results — and is empty when there are none.

In CI

Add a script and run it in your pipeline; the non-zero exit fails the job when unused operations are found:

{
  "scripts": {
    "gql:prune": "gqlprune"
  }
}

GitHub Actions annotations

Under GitHub Actions, gqlPrune emits inline ::warning annotations pointing at each unused operation/fragment (file + line), so they show up on the PR's Files changed tab. It's enabled automatically when GITHUB_ACTIONS is set, or force it anywhere with --annotate:

npx gqlprune --annotate

Annotations go to stderr, so they don't interfere with --json output on stdout (the two can be combined).

Update notifications

gqlPrune checks npm (cached, at most once a day) and prints a one-line notice to stderr when a newer version is available. It stays silent in CI and when stdout isn't a TTY, never writes to stdout (so --json stays clean), and never affects the exit code. Opt out with NO_UPDATE_NOTIFIER=1 (it's also skipped whenever CI is set).

Output

Unused operations and fragments are listed in separate sections — operations by type, name, and file; fragments by name and file:

--- Unused GraphQL Operations ---
Type     Operation       File
query    OperationName   operationFile.gql

--- Unused GraphQL Fragments ---
Fragment        File
FragmentName    fragmentFile.gql

Contributing

Contributions are welcome — see CONTRIBUTING.md. This project uses Conventional Commits; releases and the changelog are automated with release-please.

Security

See SECURITY.md for how to report a vulnerability.

Changelog

See CHANGELOG.md.

License

MIT