← Back to writingEngineering / 2026.09

Finding Problems at Scale: What 1,086 SonarQube Issues Actually Told Me

I built sonar-jira-tickets on a slow afternoon because I was tired of tabbing between SonarCloud and Jira by hand. It's a small tool, about 250 lines of Node.js with no dependencies, ESM, nothing fancy. I ran it against a real project for the first time expecting maybe a screen's worth of output. Instead my terminal filled with issue after issue and kept going. I remember sitting there scrolling and thinking, this is going to take a while to turn into tickets.

the tool itself

There's nothing clever going on under the hood, which is part of why the results surprised me. It calls the SonarCloud and SonarQube REST API at /api/issues/search, paginates 500 issues at a time, and authenticates with a personal access token sent as a Bearer header. It filters on issueStatuses=OPEN,CONFIRMED so resolved and closed noise doesn't come back. That's it. No dotenv package either, since Node 20.6.0 added native --env-file=.env support and I didn't see the point of pulling in a dependency for something the runtime already does.

One filter I deliberately left out was severity or issue type. I didn't add a flag to show only blockers, or only bugs, or anything like that. Every open and confirmed issue comes back exactly as SonarQube ranks it, from blocker down to info, bugs and vulnerabilities and code smells all mixed together. At the time that felt like the honest way to build a first version: show me everything, I'll decide what matters later. What I didn't expect was how much that single decision would shape what I learned from the output.

the numbers were bigger than I expected

Against Travelstart's white label flights repo, the tool returned 572 individual issues. Against kv-frontend, a project on a completely separate SonarQube instance that we host ourselves, it returned 1,086. Neither number was related to performance or a sign the code was falling apart. Both were pretty ordinary frontend codebases that had been growing for years without anyone running a full sweep like this.

My first instinct, looking at 572 rows of output, was to think about turning each one into a Jira ticket. That's literally what I built the tool to do. But sitting with the raw list for a few minutes made it obvious that one ticket per issue was the wrong move. Nobody triages 572 tickets in a sprint, and no team is going to look at a backlog with 572 new items and treat it as anything other than noise to be silently deprioritized forever.

one rule, 45 files, one problem

The moment that actually reframed things for me was scrolling far enough to notice the same rule appearing again and again. A Web accessibility rule, one that wants an <output> element instead of a generic status role, fired 45 separate times across 45 different Vue files in that same white label project. Same rule, same fix pattern, 45 distinct locations in the raw issue list.

Naively, that's 45 tickets. Or, if you're tracking a single number instead, it's 45 out of the 572 "open issues" the team supposedly has. Neither framing is honest about what's actually going on. It isn't 45 problems. It's one problem, a component or a pattern that got copied around without the correct semantic element, and it shows up in 45 places because the codebase repeats itself, not because there are 45 unrelated things wrong. Filing 45 tickets for it would mean 45 people each spending five minutes on the same fix in isolation, or worse, 44 of those tickets sitting untouched while the metric "572 open issues" stays flat and looks like nothing is improving even after someone fixes ten of them.

That's also why I don't trust a bare issue count as a health metric anymore. A project with 1,086 open issues that are all one recurring pattern repeated across a component library is in a completely different position than a project with 1,086 issues that are all unrelated, each one happening only once. The number alone can't tell you which one you're looking at. You have to read the list.

Tech used in this article

  • Node.js
Continue readingGrouping the list only gets a codebase back to zero once. Here's how we stopped the pattern from coming back.From SonarQube Warning to ESLint Rule: Turning Code Quality Problems Into Guardrails