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

ng-unused

v0.3.0

Published

Detect unused Angular components, services, modules, pipes, directives, routes and assets with dependency-graph accuracy

Readme

ng-unused

Detect unused and orphaned code in Angular workspaces — components, services, modules, directives, pipes, routes and assets — with dependency-graph accuracy, not text search.

ng-unused parses your TypeScript with ts-morph and your templates with the real Angular compiler (@angular/compiler), builds a typed dependency graph, and computes reachability from your application's actual entry points (bootstrapApplication / bootstrapModule and root router registrations). It understands:

  • Standalone components and NgModules (Angular 15 – 21, including the implicit-standalone default of v19+)
  • Templates: selector matching with Angular's own SelectorMatcher, structural directives, @if/@for/@switch control flow, pipes, routerLink
  • Dependency injection: constructor parameters, inject(), @Inject, providers, providedIn: 'root' | Module
  • Routing: provideRouter, RouterModule.forRoot/forChild, loadChildren, loadComponent, nested children, redirectTo, router.navigate()
  • Dynamic imports and dynamic component creation (createComponent, ComponentPortal, …)
  • tsconfig baseUrl/paths aliases
  • Assets: SCSS @use/@import chains, url() refs, images, JSON, environment files and fileReplacements

A key design decision: registration is not usage. A component declared in an NgModule (or listed in a standalone imports array) but never rendered, routed, or referenced is reported as unused — with a reason explaining where its registration must be removed.

Installation

npm install --save-dev ng-unused
# or run without installing
npx ng-unused analyze

Requires Node.js >= 18.19.

Usage

ng-unused analyze              # analyze the workspace containing cwd
ng-unused analyze src/app      # restrict reported findings to a sub-path
ng-unused component            # components only
ng-unused service              # services only
ng-unused module               # NgModules only
ng-unused directive            # directives only
ng-unused pipe                 # pipes only
ng-unused route                # routes (effective paths, broken routes)
ng-unused route --delete-plan campaign/dashboard   # safe-delete report
ng-unused graph                # dependency graph as JSON
ng-unused graph -o graph.json  # ... written to a file
ng-unused report               # write unused-report.json + unused-report.html
ng-unused explain CardComponent  # why is this used/unused?
ng-unused fix --dry-run        # preview what could be deleted automatically
ng-unused fix                  # delete everything SAFE TO DELETE (git-clean check)
ng-unused fix --unused         # also remove registration-only unused entities
ng-unused baseline             # freeze current findings; CI fails only on NEW ones
ng-unused analyze --watch      # re-analyze on save (incremental, cached)

Fix mode

ng-unused fix turns findings into changes:

  • deletes every file whose entities are all SAFE TO DELETE — including dead clusters (a component whose only referencer is a dead module goes with it) and the templates/styles/assets they exclusively own;
  • with --unused, additionally removes entities that are only registered (NgModule declarations/imports/exports) but never rendered or injected — editing the registering module and dropping the import for you;
  • never touches HIGH-risk findings (possible dynamic usage / public API);
  • refuses to run when the workspace has uncommitted changes (--force to override), so every fix is one git checkout away from being undone.

Always start with --dry-run, and build + test after applying.

Baseline (adopting on a legacy codebase)

ng-unused baseline                      # writes .ng-unused-baseline.json
git add .ng-unused-baseline.json
ng-unused analyze --baseline --fail-on-unused   # CI: fails only on NEW findings

Existing findings are suppressed; anything introduced afterwards fails the build. Stale entries (findings you fixed) are reported so you can re-capture.

Global options

| Option | Effect | | ------------------ | ------------------------------------------------------------- | | --tsconfig <p> | tsconfig for path-alias resolution (auto-detected by default) | | --json [file] | also write a JSON report (default unused-report.json) | | --html [file] | also write an HTML report (default unused-report.html) | | --fail-on-unused | exit code 1 when anything unused is found (CI gate) | | --baseline [file]| suppress findings recorded in the baseline (see above) | | --cache | incremental parse cache: only changed files are re-parsed | | --show-used | list used entities too | | --no-color | disable ANSI colors | | --verbose / --quiet | logging level |

Exit codes

0 clean · 1 unused findings with --fail-on-unused · 2 tool error.

Example output

ng-unused v0.1.0  /work/my-app
312 files scanned in 1840 ms

  Components   214 total  198 used, 9 unused, 7 safe to delete
  Services      88 total   80 used, 5 unused, 3 safe to delete
  ...

Components
  [UNUSED]         OldBannerComponent risk:MEDIUM src/app/old-banner/old-banner.component.ts:5
      Registered (declarations/imports/exports) in AppModule but never rendered or injected; ...
  [SAFE TO DELETE] GhostComponent risk:LOW src/app/ghost/ghost.component.ts:6
      No references found anywhere in the workspace.

Every finding is one of USED, UNUSED, or SAFE TO DELETE, with a risk level (LOW / MEDIUM / HIGH) and human-readable reasons. SAFE TO DELETE means: zero references anywhere and no risk signals (no dynamic creation, no module exports, no unparseable templates).

Safe delete engine

ng-unused route --delete-plan campaign/dashboard
Safe delete report for 'campaign/dashboard'  [risk: HIGH]
  'campaign/dashboard' is still reachable from the application entry points; ...

Files to delete (4):
  - src/app/campaign/dashboard/dashboard.component.ts
  - src/app/campaign/dashboard/dashboard.component.html
  - src/app/campaign/dashboard/dashboard.component.scss
  - src/app/campaign/dashboard/dashboard.service.ts

Shared files to keep (2):
  - src/app/shared/chart/chart.component.ts (also used by ReportsComponent)
  - src/app/shared/table/table.component.ts (also used by AdminComponent)

The plan is computed on the dependency graph: everything the target uses exclusively is deletable; anything live code outside the deletion set still references is listed as shared and kept.

HTML report

ng-unused report produces a fully self-contained unused-report.html (no CDNs, works offline): summary dashboard, risk analysis, delete recommendations, per-kind findings tables, routes with effective full paths, assets, and an interactive dependency-graph view.

Programmatic API

import { WorkspaceAnalyzer, JsonReporter } from 'ng-unused';

const session = new WorkspaceAnalyzer().analyze({ rootDir: '/work/my-app' });
console.log(session.result.summary.components);
const plan = session.safeDelete.plan('campaign/dashboard');
new JsonReporter().write(session.result, 'unused-report.json');

See docs/API.md for the full surface.

Architecture

Scanner → TypeScript Parser → Angular Template Parser
        → Dependency Graph Builder → Reference Engine
        → Risk Engine → Report Generator

Monorepo packages, each with a single responsibility:

| Package | Responsibility | | --------------------- | ---------------------------------------------------------- | | @ng-unused/shared | types, constants, errors, logging, path utilities | | @ng-unused/parser | ts-morph TypeScript parser + @angular/compiler templates | | @ng-unused/graph | typed bidirectional dependency graph + builder | | @ng-unused/analyzer | scanner, reference engine, risk engine, analyzers, planner | | @ng-unused/reporter | console, JSON and HTML report generators | | ng-unused (cli) | commander CLI |

Details in docs/ARCHITECTURE.md.

Performance

Designed for large workspaces (2000+ components, 5000+ files, 100+ lazy modules): every file is read once (shared file cache), the TypeScript project is syntax-only (no type checker, no lib files), import resolution is memoized, and the graph indexes both edge directions for O(degree) traversal.

Accuracy notes

Static analysis is conservative by design:

  • Entities passed to dynamic-creation APIs are never marked safe to delete.
  • Providers of live modules count as used even if never injected (token indirection like { provide: X, useClass: Y } cannot always be traced).
  • Templates that fail to parse raise the risk of every unused component/directive/pipe, since usage could hide there.

Contributing

See CONTRIBUTING.md. Run npm install, npm run build, npm test, npm run lint at the repo root; example apps in examples/ are the integration fixtures.

License

MIT