Languages / Apex (Salesforce)

Salesforce Apex code analysis: dead code, call graphs and org metadata

To find unused Apex classes in a Salesforce project, you need the metadata, not only the .cls files: a class may be called from a Flow, an Aura component or a Visualforce page. repowise reads the sfdx project and links Apex to LWC, Aura, Visualforce, Flows and object metadata, then reports unused Apex with a confidence, a reason and the owner of each file.

Last reviewed: November 2026

Full tier

What repowise detects in Apex (Salesforce)

Checked against the engine source. Every row runs locally with zero LLM calls.

repowise capabilities for Apex (Salesforce)
Files parsed.cls, .trigger, .apex, plus LWC, Aura, Visualforce, Flow and object metadata files
Import resolutionName resolution: one sfdx project is one case-insensitive namespace; npsp.Foo style prefixes resolve to repo projects of that namespace
Call graphYes, including Apex to and from metadata
Dead codeFindings with confidence, reason and owner, checked against Flow, Aura, LWC and Visualforce metadata
Health markersComplexity, class metrics, Extract Method plans, plus 4 Apex-only advisory markers
Performance markersSOQL, SOSL and DML inside loops, Database.* calls, callouts, Messaging.sendEmail, System.enqueueJob and @future calls in loops
Coverage reportsApex test-run coverage JSON (orgWideCoverage, testRunCoverage, deploy results)
Frameworks recognisedLWC tags and bindings, Aura controllers and helpers, Visualforce controllers and extensions, Flows (Apex actions, @InvocableMethod, subflows), @RestResource, flexipages, quick actions, tabs, email services, Experience sites

Specific to this language

How Apex (Salesforce) code is read

Metadata is part of the graph

A Flow calling an @InvocableMethod, an Aura component naming its controller, a Visualforce page with controller= and extensions=, and LWC <c-child> tags all become edges. Flexipages, quick actions, tabs, email services and Experience sites are entry points. Objects become class symbols and fields become property symbols.

Four Apex-only markers

apex_soql_injection, apex_missing_sharing (a class with SOQL or DML and no sharing keyword), apex_hardcoded_id and apex_see_all_data (@IsTest(SeeAllData=true)) are advisory: they appear on the file and never move its score.

Dead code checked against org metadata

Salesforce resolves some names at runtime, and code can be referenced from Flows, Aura, Visualforce and object metadata. repowise reads that metadata from the sfdx project and lists each Apex finding with its confidence and owner. Static-resource third-party libraries are treated as vendored.

Honest comparison

Native Apex (Salesforce) tools, and when they are enough

Native Apex (Salesforce) analysis tools
ToolWhat it covers
Salesforce Code AnalyzerSalesforce's scanner bundling PMD, ESLint and other engines, run through the sf CLI.
PMD Apex rulesUnused locals, complexity, and OperationWithLimitsInLoop for SOQL and DML in loops.
MetadataComponentDependency (Tooling API) and Where is this used?Org-side references between metadata components, read from the live org.
sf apex run test --code-coverageOrg test runs with coverage; the JSON output is read by repowise.

Where repowise adds value

  • A repository-wide graph across Apex, LWC, Aura, Visualforce and Flows, with communities and C4 views.
  • Unused-class candidates that account for metadata references, ranked by git history.
  • Hotspots and ownership in orgs where many admins and developers commit.
  • Agent context: an agent can ask what calls an Apex method, including Flows, before changing it.

How to run it

Analyse a Apex (Salesforce) repository

From the repository root. Agents get the same results through the get_dead_code, get_health and get_context MCP tools.

uv tool install repowise        # or: pipx install repowise
repowise init --yes --no-prose     # index the repo, no API key
repowise dead-code --min-confidence 0.7 --safe-only
repowise health --refactoring-targets
sf apex run test --code-coverage --result-format json --output-dir test-results
repowise coverage add test-results/test-result-codecoverage.json
repowise serve                     # graph, health and dead code in a local dashboard

Questions

What people ask before they try it.

How do I find unused Apex classes?

Retrieve the metadata into an sfdx project, then run repowise dead-code. Apex reached from LWC, Aura, Visualforce, Flows, REST resources or tests is live; the rest is listed for review with a confidence. Confirm against the org before deleting, since references outside the repository are invisible.

Does it check SOQL and DML inside loops?

Yes. Inline SOQL, SOSL and DML in loops, Database.* calls, callouts, sendEmail, enqueueJob and @future calls in loops are flagged as performance markers.

Does it read Apex code coverage?

Yes. repowise coverage add accepts the org-wide and test-run coverage JSON from Apex test runs and deploy results.

Does it work for managed packages with namespaces?

Namespace prefixes resolve to projects in the repository that declare that namespace in sfdx-project.json or cumulusci.yml. Unnamespaced dependency packages are followed.

Does repowise send my Apex code to an LLM?

No. Parsing, the call graph, dead code, health scores, performance markers and git history all run locally with zero LLM calls. repowise init --yes --no-prose needs no API key, and the analysis itself makes no network calls. Written documentation prose is the one opt-in step that uses a model, and it can run on a local Ollama model.

Index a Apex (Salesforce) repository.

Public repositories are free on repowise.dev. The CLI is open source and runs on your machine with no API key.