Static analysis tools read your code without running it — and that's exactly their advantage. By the time a bug surfaces at runtime, it's already a user problem. Tools like SonarJS find it during development, before the code ships.

What SonarJS Actually Does

SonarJS is a static analyzer for JavaScript and TypeScript that works through two complementary techniques: dataflow analysis and pattern matching. Pattern matching is the simpler one — it flags known bad patterns, the kind ESLint catches. Dataflow analysis goes further: it traces how values move through your program, which lets it spot things like null dereferences, unreachable code, and tainted data reaching a sensitive operation without being sanitized first.

Internally, SonarJS parses source into an Abstract Syntax Tree and then walks that tree with its rule visitors. Each visitor checks a node, navigates the surrounding tree for context, and logs an issue if something looks wrong. The AST step is what separates a real analyzer from a regex-based linter — the tool understands structure, not just text.

The practical upshot: SonarJS ships with around 190 rules, roughly 60 of which target outright bugs (the rest cover code smells and security vulnerabilities). It supports modern ECMAScript, React JSX, Vue.js, and Flow type annotations. You can also import your existing ESLint results and test-coverage reports, so SonarJS can correlate static findings with coverage gaps — untested paths that also contain suspicious code are worth extra attention.

Running It: SonarQube or the Scanner

SonarJS typically runs as a plugin inside a SonarQube server. The setup is a few steps:

1. Install and start a SonarQube server (self-hosted or SonarCloud). 2. Install the SonarQube Scanner — a CLI tool that feeds your source to the server. 3. Install the SonarJS plugin into SonarQube. 4. From your project root, run sonar-scanner, passing your project key, source directory and server URL as parameters.

sonar-scanner -Dsonar.projectKey=my-project -Dsonar.sources=.

After the scan completes, SonarQube prints a dashboard URL where you can browse issues by severity, rule, and file. For repeatable runs you can move those parameters into a sonar-project.properties file in the project root, keeping the CLI invocation clean.

Quality profiles control which rules fire. Two ship by default: Sonar Way (a conservative baseline) and Sonar Way Recommended (a broader set, including more opinionated rules). Start with Sonar Way and layer in Recommended once you've cleared the initial backlog — don't let a wall of warnings become background noise from day one.

Writing Custom Rules

The built-in rules cover a lot, but teams with domain-specific patterns — unsafe API calls, proprietary error-handling conventions — can write their own. Custom rules are authored in Java against the SonarJS plugin API.

The process: create a SonarQube plugin project and wire it to SonarJS via Maven (pom.xml). Implement two extension points: RulesDefinition (which registers the rule's metadata — key, name, description) and CustomRuleRepository (which registers the rule class itself so SonarJS invokes it during analysis). The rule class extends either SubscriptionVisitorCheck or DoubleDispatchVisitorCheck and uses Java annotations to declare its key, name, and tags.

For logging issues, you have two methods. addIssue(tree, message) produces a PreciseIssue that highlights a specific code range in the SonarQube UI — the right choice for most rules. addIssue(issue) with a manually constructed FileIssue is for file-level findings that don't map to a specific line.

Why Bother Beyond ESLint?

If you already have a linting setup that catches real bugs, you might wonder whether SonarJS adds enough to justify the overhead. The honest answer: for a small project or a solo developer, probably not. For a team shipping production code, the dataflow-based rules catch a class of bugs that pattern-matching linters simply can't — cross-function null propagation, security sinks, unreachable branches hidden behind complex control flow. The SonarQube dashboard also gives engineering leads visibility across the whole codebase over time, which ESLint reports alone don't provide.

Static analysis doesn't replace tests, code review, or good judgment. It's another layer — one that's tireless, consistent, and doesn't need to be reminded to check every pull request.