# codeql-action: two steps, three build modes, and a licence that decides who may run it

> codeql-action runs the CodeQL semantic analysis engine in GitHub Actions and uploads results to code scanning, and it also accepts SARIF from any other tool. The interesting decisions are not the analysis but the build mode and the fact that the action itself is MIT while the CLI behind it is not.

**github/codeql-action** — Actions for running CodeQL analysis

- Repository: https://github.com/github/codeql-action
- Stars: 1,657 · Forks: 498
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/github-codeql-action

## init, analyze, and one action that is not for you

The repository contains several actions, and only two of them are the ones you wire into a workflow. `init` sets up CodeQL for analysis, and `analyze` finalizes the CodeQL database, runs the analysis, and uploads the results to Code Scanning.

A third, `upload-sarif`, uploads a SARIF file to Code Scanning, and the README is pointed about when to use it: if you are already using the analyze action there is no reason to use this one as well. That action exists so any SARIF-producing SAST tool can feed the same results store, which makes code scanning the destination rather than the product.

Then there are the actions the README calls special purposes and unlikely to be used directly. `autobuild` attempts to build the code automatically, and the instruction is to use the `build-mode: autobuild` input on init instead of calling it. `resolve-environment` is experimental and infers a build environment. `setup-codeql` is experimental and like init but only installs the CLI without creating a database. `start-proxy` is experimental, internal use only, and the README says it will change without notice.

That last warning is the one to notice. Anything marked internal and unstable should not appear in your workflow file, even though it is in the same repository.

## Three build modes, and the choice changes your results

How CodeQL sees your code depends entirely on the build mode, and the README's guidance is more nuanced than the summary usually suggests.

`none` creates the database without building the source. It is available for all interpreted languages and some compiled ones. Interpreted languages must use `none`.

`autobuild` attempts to build the source automatically and is available for all compiled languages. It is the simplest option, but it only works for projects with generic build steps that the autobuild heuristics can guess. If it fails you must switch to `manual` or `none`. If it succeeds, the README states that results and run time are the same as manual mode.

`manual` builds with a command you specify, with the build steps placed in the workflow between init and analyze. It typically produces the most precise results and is more difficult to set up, and the analysis takes slightly longer.

The caveat on `none` is the one that catches people: it is simpler and slightly faster, but alerts can be missed if your repository does code generation during compilation, or if dependencies downloaded from registries are not reachable from the workflow. And it is not yet supported by Swift, Go or Kotlin, while for C and C++ it is in public preview.

## Two permissions, and the private repository case has an extra one

The workflow permission requirements are short and non-negotiable. All advanced setup code scanning workflows must have the `security-events: write` permission, and workflows in private repositories must additionally have `contents: read`.

The reason to state these plainly is that a missing permission fails at the upload step rather than at the analysis step, which means you get a completed analysis and then a failed job. A `permissions:` block at the top of the job is the usual fix.

If you are not writing the workflow by hand, the README recommends default setup, configured through GitHub's code scanning settings rather than a YAML file. Advanced setup is the alternative when you need a highly customisable scanning configuration, and the README links separate pages for setting it up and for customising it afterwards. That ordering, default first and advanced only when the default is insufficient, is the sensible one.

## The MIT label covers the wrapper, not the engine

The licence section is short and the distinction in it matters more than anything else in this article.

The project is released under the MIT License, and LICENSE is at the repository root, with package.json declaring the same. That is the code of the action itself: the TypeScript in src/, the action definitions, the build scripts.

The underlying CodeQL CLI, which the action invokes, is licensed separately under the GitHub CodeQL Terms and Conditions. The README states the consequence directly: this action may be used on open source projects hosted on GitHub, and on private repositories owned by an organisation with GitHub Advanced Security enabled.

That is not a formality for an enterprise. Running CodeQL on a private repository outside an organisation with Advanced Security is outside the stated permission, regardless of how the action itself is licensed. Anyone reading the MIT badge on the repository and concluding their private commercial repository is covered has misread the document.

This paragraph describes what the README states about the terms and is not legal advice; the linked terms and your own procurement review are the authority for a specific case.

## v4 and v3 are both supported, and both were released the same day

The supported versions are v4, which is latest, and v3. Both are maintained in parallel, and the release history shows why that matters: v4.39.0 and v3.39.0 were both tagged on 2026-10-15, with v4.38.3 on 2026-10-08.

Same-day releases across both lines means a team on v3 and a team on v4 are both getting fixes at once, which is the maintenance model you want from a security tool.

The last push was on 2026-10-16, so main is active between releases rather than sitting still. package.json already declares version 4.39.1, one patch ahead of the newest tag, which is ordinary for a repository that merges before it tags.

The repository also keeps an unreleased-change-notes/ directory alongside CHANGELOG.md, and a CODEOWNERS file. The README's first section points at the changelog for recent changes, which is where to look when an upgrade changes behaviour.

## GitHub Enterprise Server has its own compatibility table

If you run GitHub Enterprise Server rather than github.com, the version story is different and there is a table for it.

The stated policy is that new minor versions of the CodeQL Action and Bundle are typically released when a new minor version of GHES is released, and when a GHES version is deprecated, the Action and Bundle releases that shipped with it are deprecated as well. The pairing is explicit: v4.36.2 needs CodeQL Bundle 2.25.6 on Enterprise Server 3.22, v4.33.0 needs Bundle 2.24.3 on 3.21, and v4.31.10 needs Bundle 2.23.9 on 3.20, with v3.29.11 paired with Bundle 2.22.4 in the same table.

Two practical consequences follow. On GHES you are pinned to the Action versions validated against your server release, so the v3 and v4 parallel support above does not apply in the same way. And the Bundle is a separate artifact from the action, which means an upgrade is a two-part decision rather than one.

The table in the README is the version you should check before upgrading either piece, rather than assuming the latest action works on an older server.

## What the repository looks like as a codebase

The repository is TypeScript with each action in its own top-level directory: init/, analyze/, autobuild/, resolve-environment/, setup-codeql/, start-proxy/ and upload-sarif/, each with its action.yml. Queries/ and python-setup/ are also present, alongside lib/, src/, tests/ and scripts/.

The build is a TypeScript compile followed by a bundling step, and the package scripts show the sequence: `build` runs a node-modules check, then transpile, then node build.mjs. `transpile` is tsc over tsconfig.json, and the `_build_comment` script explains why the build runs before tests, so the project is typechecked and the tests reuse the transpiled files. Tests run on ava.

There is a justfile alongside the Makefile-style npm scripts, offering lint, sync, build, test, a single-file test target and a refresh-lib recipe that deletes lib/ and rebuilds. That refresh-lib recipe tells you the lib/ directory is generated and checked in, which is why .git-blame-ignore-revs exists at the root.

The lint setup is worth noting because it is self-referential: lint-ci runs eslint with the SARIF formatter and writes eslint.sarif, which means this repository analyses itself with the format it uploads. Dependencies include node-forge, long, archiver, semver, js-yaml, undici and the usual @actions and @octokit packages.

## Conclusion

Adopt codeql-action if your repositories are on GitHub and you want security findings on pull requests without running a scanner yourself, and start from default setup rather than advanced setup. Do not assume the MIT licence on the action extends to the engine: the README states the CodeQL CLI is under GitHub CodeQL Terms and Conditions, permitted for open source projects on GitHub and private repositories in organisations with GitHub Advanced Security. Verify first which build mode your language supports, since none is not yet supported by Swift, Go or Kotlin and is only in public preview for C and C++.

## FAQ

### What permissions does a CodeQL workflow need?

All advanced setup code scanning workflows must have the `security-events: write` permission. Workflows in private repositories must additionally have `contents: read`. Without them the analysis runs but the upload step fails.

### Which CodeQL build mode should I use?

Interpreted languages must use `none`. For compiled languages, `manual` gives the most precise results but is harder to set up, `autobuild` is simpler and gives the same results when it succeeds, and `none` is fastest but can miss alerts from code generation or unreachable registries.

### Can I upload results from a non-CodeQL SAST tool?

Yes. The `upload-sarif` action uploads a SARIF file to Code Scanning. The README notes that if you already use the analyze action there is no reason to use upload-sarif as well.

### What license does codeql-action use and can I use it on private repositories?

The action is MIT licensed. The CodeQL CLI it invokes is under the GitHub CodeQL Terms and Conditions, which the README says permit use on open source projects hosted on GitHub and on private repositories owned by an organisation with GitHub Advanced Security enabled.

### Which versions of codeql-action are supported?

v4 (latest) and v3, and both were released on 2026-10-15. On GitHub Enterprise Server the available versions are pinned to your server release, with a table mapping each minimum action version to a minimum CodeQL Bundle version and GHES version.

## Sources

- [github/codeql-action on GitHub](https://github.com/github/codeql-action)
- [Issues](https://github.com/github/codeql-action/issues)
- [License: MIT](https://github.com/github/codeql-action/blob/main/LICENSE)
- [README](https://github.com/github/codeql-action/blob/main/README.md)
- [Releases](https://github.com/github/codeql-action/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/github-codeql-action
