Why you're reading this
You're building or auditing a CI pipeline. Your team agrees that SAST (static application security testing) belongs in it. But the market offers three mature, credible tools—Semgrep, CodeQL, SonarQube—and each claims to be the right fit. All three find bugs. The difference is how they integrate into your workflow, how much tuning they need, and whether your team will actually look at the results.
This is not a feature checklist or a vendor comparison. It's a practical framework for choosing one (or combining two) based on your constraints: language stack, team size, appetite for custom rules, and how much server infrastructure you want to manage.
1. What SAST actually catches—and what it doesn't
SAST runs on source code without executing it. That's its strength and its ceiling. Pattern-matching tools (like Semgrep) scan for known signatures—hardcoded secrets, SQL injection vulnerability shapes, insecure randomness. Dataflow-aware tools (like CodeQL) build a model of how data flows through your code and flag paths that violate safety rules.
Neither catches logic flaws, race conditions, or business logic vulnerabilities. Neither can reason about runtime behavior, third-party library exploits you haven't patched, or deployment misconfigurations. SAST also generates false positives: flagged code that isn't actually vulnerable, usually because the tool couldn't prove the input comes from an attacker. A 30% false-positive rate is common. If your team dismisses half the findings, SAST stops being effective.
This is why the best security teams treat SAST as one layer. Pair it with dependency scanning (for vulnerable libraries), container scanning, and manual code review. SAST is necessary. It's not sufficient.
2. Semgrep: Architecture and posture
Semgrep is pattern-matching, not dataflow analysis. You write rules (or use community/Semgrep-published ones) in YAML or a custom DSL called Semgrep rule language. A rule describes a code pattern—a function call, a variable assignment, a regex—and Semgrep's engine searches for matches.
The architecture is simple: parse source files, match patterns, report results. No database, no server (unless you buy Semgrep Pro). Open-source Semgrep runs on your machine or in CI. The Pro tier adds cloud-hosted rules, IDE integration, PR comments, and policy management.
Strengths: Semgrep is fast—a codebase of 100k lines typically scans in seconds. Rules are easy to write, especially for language-specific checks. Custom rules are Semgrep's killer feature: you can encode your own patterns (antipatterns your team keeps introducing, your framework's pitfalls) without waiting for Semgrep to add them. Language support is broad: Python, JavaScript, Go, Java, C, C++, Ruby, PHP, and more. CI integration is frictionless—it's a CLI tool that exits with a code.
Weaknesses: Semgrep Community Edition's pattern matching doesn't understand cross-file dataflow — the Pro tier adds cross-file and cross-function taint tracking, which significantly improves detection of complex vulnerabilities. Without Pro, you'll miss some real vulnerabilities and get more false positives. Serious use means a Pro subscription, which scales with team size. Compiled languages (C, C++) get partial support—pattern matching works, but dataflow is limited.
3. CodeQL: Architecture and posture
CodeQL is GitHub's bet on dataflow. You write rules in QL, a query language that operates over a database of code relationships—which variables point to which values, which functions call which functions, etc. The first step is slow: CodeQL compiles your code into a database. Once built, querying is flexible.
Strengths: Dataflow analysis is deeper than Semgrep. CodeQL can track how a user-controlled string flows through your code—through function calls, array operations, string concatenations—and flag it if it reaches a vulnerable sink. For a codebase with complex data pipelines, this is significantly more useful. Free for public repositories on GitHub. Integrated into GitHub Advanced Security (GHAS), so it runs in Actions. QL itself is expressive; once you've written a few queries, you can encode nuanced logic.
Weaknesses: The database build is slow. A 500k-line monorepo might take 5–15 minutes to build a database. QL has a learning curve; it's not YAML. You're locked into GitHub if you want to run CodeQL natively—the cloud offering exists, but the experience is GitHub-first. Outside GitHub, setup is more manual. Commercial support is minimal; mostly documentation and community.
4. SonarQube: Architecture and posture
SonarQube is a centralized server that runs analysis on uploaded code snapshots. You run SonarScanner on your machine or in CI, which sends code and metadata to the SonarQube server. The server runs static analysis, generates reports, and tracks trends over time. It's broader than SAST—SonarQube includes code quality, test coverage, and security in a single dashboard.
Strengths: Language support is the broadest of the three. SonarQube covers 30+ languages. IDE integration is good; your team can see findings in their editor in real time. Quality gates—pass/fail criteria for PRs—are built in and flexible. If you want a unified view of code quality and security in one tool, SonarQube is your answer. Editions exist for different scales: Community (free, self-hosted), Developer (self-hosted, with more rules and features), and Enterprise (with portfolio management).
Weaknesses: You're running a server. That's operational overhead: upgrades, backups, disk space, memory tuning. Security rules are less aggressive than Semgrep or CodeQL out of the box; you'll likely tune them down anyway. Dataflow analysis is available but not as refined. Pricing for Beyond Community editions is per-developer, which adds cost as teams grow. The tool tries to do everything—quality, coverage, security—which means no single aspect is best-in-class.
5. Head-to-head: Speed, accuracy, coverage
Speed: Semgrep is fastest. Most runs complete in under a minute. CodeQL's database build is the overhead; after that, queries are fast. SonarQube's scan time depends on server resources and language; expect 2–10 minutes for medium codebases.
True positive rate: CodeQL and Semgrep perform similarly on common vulnerabilities. SonarQube lags slightly because its security rules are less aggressive. On false positives, SonarQube is often noisier out of the box, especially for code-quality violations that aren't security issues.
Language support: SonarQube wins breadth. Semgrep covers most popular languages well. CodeQL supports fewer languages, but with deeper analysis on supported ones.
Custom rules: Semgrep is easiest. Writing a Semgrep rule takes minutes. QL is slower. SonarQube custom rules exist but are less accessible.
CI integration: Semgrep and CodeQL are native cloud-first. SonarQube requires a server, adding deployment complexity. All three can comment on PRs or fail the build based on findings.
Cost: Semgrep OSS is free; Pro tiers start around $50/month and scale to $5k+/month for large teams. CodeQL is free for public repos, ~$21/month per seat for private repos (GHAS). SonarQube Community is free; Developer edition is ~$100/year per developer; Enterprise pricing is negotiated.
6. Decision framework: Choose based on constraints
Use Semgrep if: You need to ship quickly, your team is under 20 engineers, your stack is modern languages (Python, Go, JavaScript, Java), you want to write custom rules without learning a query language, and you're willing to manage cloud or open-source infrastructure. Semgrep is the path of least resistance for most startups and smaller teams. It's also the right choice if custom rules are a priority—your team has specific antipatterns you catch in code review and want automated.
Use CodeQL if: You're on GitHub, your codebase is complex and dataflow-heavy (e.g., a web framework or financial system), you're comfortable with query languages, and you want integration with GitHub Advanced Security. CodeQL shines on vulnerability classes that require deep taint tracking. If you're already paying for GitHub Enterprise, CodeQL is included; the case for it is stronger.
Use SonarQube if: You need to cover 20+ languages, you want one unified tool for quality and security, your team has been using SonarQube already, or you have the infrastructure to run a self-hosted server. SonarQube is the legacy/enterprise choice. If you're evaluating from scratch and have no SonarQube investment, Semgrep or CodeQL are likely faster to value.
7. Combining tools: When one isn't enough
Many teams don't choose one. The common pattern is Semgrep for custom rules + CodeQL for deep dataflow. Both are cloud-native, both are fast enough to run on every commit, both integrate with GitHub. Use Semgrep for your team's specific checks, CodeQL for the vulnerability classes that need taint tracking.
Alternatively, Semgrep + SonarQube for teams that need breadth (SonarQube's language support) and opinionation (Semgrep's custom rules). Run SonarQube nightly, Semgrep on every PR.
The rule: don't run the same tool twice. If you use CodeQL, Semgrep OSS rules are redundant. If you're already on SonarQube, add Semgrep for your custom checks, not SonarQube Security again.
8. Making any of them work: Tuning, ownership, and feedback loops
Here's where most teams fail: they pick a tool, run it, and drown in findings. A typical SAST tool finds 100+ issues in a mature codebase. If your team doesn't triage, suppress, and own each finding, the tool becomes noise.
Best practice: disable rules you don't plan to act on. Start with a small, high-confidence ruleset. If you're using Semgrep, comment out rules in your config file rather than silencing findings per-PR. If you're on CodeQL, use the security/code-scanning suite, not "all queries"—there are 300+ queries out there. If you're on SonarQube, lower the severity threshold initially; add rules as your team learns to handle them.
Second: own findings by person or team. In your GitHub/CI system, assign a finding to a PR author or a security champion who reviews before merge. The PR-level feedback loop is critical. If developers never see SAST results until post-merge, they won't care.
Field observation: A team that ran Semgrep with 50 active rules and a suppression file for pre-existing issues resolved 90% of new findings within a sprint. A team that ran the same tool with 200 rules enabled and no suppression strategy got 10 findings per PR and disabled the tool after two weeks.
Field observation: One SonarQube deployment had the default security profile enabled, which included rules about missing javadoc and code duplication. Those aren't security issues. The team tuned to 40 security-only rules, saw 5 findings per PR, and treated them seriously.
The short version
Semgrep is fastest to deploy and best for custom rules; use it if you're under 50 engineers and on modern languages. CodeQL is strongest on dataflow and best integrated with GitHub; use it if you're GitHub-native and need to catch complex taint flows. SonarQube is broadest in language support and best for teams that need one tool for quality and security; use it if you have server infrastructure and cover 10+ languages.
Whichever you choose, start with a tight ruleset, own findings by person, and give developers PR-level feedback. A tool with 30 high-confidence rules and 80% developer engagement is more effective than a tool with 200 rules and 5% engagement. The difference between tools is real but smaller than the difference between a tuned tool and an untuned one.
Want us to choose and tune SAST for your stack?
We evaluate your codebase, pick the right tool, write custom rules for your patterns, and tune it until developers actually act on the findings.