Integrating Qodana Static Analysis into a GitHub Actions Pipeline
Add Qodana to your CI with a single workflow file, cache results for speed, and push SARIF to GitHub Code Scanning. Learn the exact steps, pitfalls, and how to verify the output.
17 Jun 2026, 06:16 UTC

Why Qodana in CI?
Qodana is JetBrains’ lightweight static‑analysis engine that runs inside a Docker container. It can analyze any language that IntelliJ IDEA supports (Java, Kotlin, JavaScript, Python, etc.) and outputs an HTML report and a SARIF file that GitHub can consume. Running it in CI ensures every commit gets checked without manual effort.
Get the Right Files in Place
- Place a
.qodana.ymlin the repository root. This file tells Qodana which inspection profile to use, where to look for source code, and how to format reports.# .qodana.yml profile: "Default" # Optional: change the target directory if the repo layout is non‑standard target: "src" # Report formats – HTML for human review, SARIF for GitHub report: format: html output: .qodana/report.html sarif: .qodana/report.sarif - Add a GitHub Actions workflow. Create
.github/workflows/qodana.yml.name: Qodana Static Analysis on: push: branches: [main] pull_request: branches: [main] jobs: qodana: runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v4 - name: Cache Qodana results uses: actions/cache@v3 with: path: .qodana/cache key: ${{ runner.os }}-qodana-${{ hashFiles('.qodana.yml') }} restore-keys: ${{ runner.os }}-qodana- - name: Run Qodana uses: JetBrains/qodana-action@v1 with: qodana-token: ${{ secrets.QODANA_TOKEN }} cache-dir: .qodana/cache working-directory: . - name: Upload SARIF to GitHub Code Scanning if: always() uses: github/codeql-action/upload-sarif@v2 with: sarif_file: .qodana/report.sarif checkout_path: .
How the Workflow Works
- The
actions/checkoutstep mounts the repository into the runner’s workspace. - The cache step stores the Qodana cache directory (
.qodana/cache) between runs. The cache key uses the hash of.qodana.ymlso that a change to the inspection profile forces a full reanalysis. - The
JetBrains/qodana-actionruns the Qodana Docker image. It mounts the repository at/srcinside the container, sets the working directory to the repository root, and points to the cache directory. - After analysis, Qodana writes an HTML report and a SARIF file into
.qodana. - The SARIF file is uploaded to GitHub Code Scanning, making findings visible in the repository’s Security → Code Scanning tab.
Verifying the Setup
- Run the workflow locally with
actto confirm it completes:act -j qodana # Check that .qodana/report.html and .qodana/report.sarif exist - Push a change that introduces a known issue (e.g., an unused variable) and open a PR. The workflow should generate a SARIF that contains that issue.
- In the GitHub UI, navigate to Security → Code Scanning and verify that the Qodana alert appears under the repository’s alerts list.
Common Pitfalls and How to Avoid Them
- Missing
.qodana.ymlor wrong path. Qodana will silently skip analysis if it cannot find the config. Always commit the file to the root of the repo. - Incorrect working directory. The container expects the source at
/src. If your repo layout differs, set thetargetfield accordingly. - Over‑aggressive caching. Including
.gitor other transient files in the cache can cause stale results. Cache only the.qodana/cachedirectory. - Non‑existent inspection profile. If the profile name in
.qodana.ymlis misspelled, Qodana falls back to defaults and may miss critical checks. Verify the profile name against IntelliJ’s available profiles. - No SARIF upload. Forgetting the
upload-sarifstep means findings stay hidden. Theif: always()guard ensures the upload runs even if analysis fails.
Limitations to Keep in Mind
- Qodana supports only languages that IntelliJ IDEA can analyze. Adding unsupported files (e.g., raw assembly) will be ignored.
- The Docker image size (~300 MB) can increase workflow runtime, especially on first run when the cache is empty.
- Large repositories may hit GitHub Actions limits on artifact size. Keep the SARIF file under the 100 MB artifact limit by pruning unnecessary data in
.qodana.yml. - Running Qodana in a public repository requires a
QODANA_TOKENsecret if you want to use a private inspection profile. Without it, the action will use the public default profile.
Conclusion
By adding a minimal .qodana.yml and a single workflow file, you can enforce consistent static analysis across all branches. Caching speeds up the pipeline, and SARIF integration gives developers clear, actionable feedback inside GitHub. Follow the checklist above to avoid common mistakes and verify that your setup works before relying on it in production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.