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.
| Files parsed | .cls, .trigger, .apex, plus LWC, Aura, Visualforce, Flow and object metadata files |
|---|---|
| Import resolution | Name resolution: one sfdx project is one case-insensitive namespace; npsp.Foo style prefixes resolve to repo projects of that namespace |
| Call graph | Yes, including Apex to and from metadata |
| Dead code | Findings with confidence, reason and owner, checked against Flow, Aura, LWC and Visualforce metadata |
| Health markers | Complexity, class metrics, Extract Method plans, plus 4 Apex-only advisory markers |
| Performance markers | SOQL, SOSL and DML inside loops, Database.* calls, callouts, Messaging.sendEmail, System.enqueueJob and @future calls in loops |
| Coverage reports | Apex test-run coverage JSON (orgWideCoverage, testRunCoverage, deploy results) |
| Frameworks recognised | LWC 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
| Tool | What it covers |
|---|---|
| Salesforce Code Analyzer | Salesforce's scanner bundling PMD, ESLint and other engines, run through the sf CLI. |
| PMD Apex rules | Unused 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-coverage | Org 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 dashboardQuestions
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.
Related reading
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.