Static Analysis
Date: 2026-08-17
Examining code without running it. Linting and type checking are the familiar members; the more useful and less used ones answer questions about the codebase as a whole — what depends on what, what’s unreachable, and what’s getting worse.
Static analysis derives properties of a program from its source, without executing it.
The family
| Tool | Question |
|---|---|
| Linter | Does this match our rules? — Linting |
| Type checker | Are the types consistent? — Type Checking in CI |
| Dependency analysis | What imports what? |
| Dead code detection | What’s never reached? |
| Complexity metrics | Which code is hardest to change? |
| Security scanning | Are there known-vulnerable patterns? |
| Bundle analysis | What ends up shipped? — Bundle Analysis |
The first two are near-universal; the rest are where the unexploited value is.
Dependency rules
The most useful under-used capability: enforcing architectural boundaries in code rather than in a document.
INTENDED
features/checkout → shared/ui
features/checkout → shared/api
features/checkout ✗ features/account
ACTUAL, after 18 months
everything imports everything
Architecture documented in a diagram erodes silently. Enforced by a tool, it can’t:
"import/no-restricted-paths": ["error", {
"zones": [{
"target": "./src/features/checkout",
"from": "./src/features/account",
"message": "Features must not import
each other — use shared/"
}]
}]This turns a convention into a constraint, and it’s the single highest-value static analysis rule most codebases don’t have — Coupling and Cohesion.
Circular dependencies are the related check. They break tree-shaking, cause confusing initialisation-order bugs, and indicate the module boundary is wrong.
Dead code
UNUSED EXPORTS exported, never imported
UNREACHABLE CODE after a return
UNUSED FILES in no import graph
UNUSED DEPENDENCIES declared, never imported
UNUSED CSS harder — dynamic classes
defeat it
Tools like knip and depcheck find these, and the results are usually surprising — a mature codebase carries a lot of code nobody has referenced in years.
Deleting dead code is the cheapest possible improvement: smaller bundles, faster builds, less to read, less to maintain, fewer dependencies to keep current.
The caveat: dynamic imports, string-keyed lookups and framework conventions defeat the analysis, so verify before deleting rather than trusting the report.
Complexity metrics
CYCLOMATIC COMPLEXITY independent paths
through a function
COGNITIVE COMPLEXITY how hard it is for a
HUMAN to follow
← the more useful of
the two
FILE LENGTH crude, and correlates
FUNCTION LENGTH with pain
Use them as a signal, never as a target. A high-complexity function is worth looking at; a rule failing the build at a threshold produces artificially split functions that are no easier to understand — and Goodhart’s law applies immediately.
The genuinely useful application is the trend. Complexity rising in a module over months indicates where the design is straining, which is a better prompt for refactoring than anyone’s opinion — Abstraction and Leaky Abstractions.
Security scanning
SAST source scanned for
vulnerable patterns
DEPENDENCY known CVEs in packages
SCANNING — Dependency Management
SECRET credentials committed
SCANNING — Secrets Management
IaC SCANNING misconfigured infrastructure
See: Dependency Management · Secrets Management
Secret scanning is the one to have first, because it’s high-signal, low-noise, and the failure it prevents is severe. SAST tools are noisier and need triage discipline or they get ignored like any other wall of warnings.
Making it stick
- Fail the build on new violations, not on the backlog. A ratchet, not an ultimatum
- High signal-to-noise. One tool producing 30 real findings beats four producing 800 mixed ones
- Run it where the feedback is useful — the editor first, CI as the gate
- Delete rules nobody acts on. A permanently-failing check is a check that has been switched off socially
The recurring failure across every tool here is noise. Any output people learn to skip past has negative value, because it also hides the findings that mattered.