CodeQL can analyze C# applications on Linux ARM64 runners, which makes ARM-based GitHub Actions infrastructure a practical option for teams that build and test .NET applications on ARM.

The important part is making sure the runner, .NET SDK, CodeQL tooling, dependencies, and build mode all work together. A workflow that works on an x64 runner should not be assumed to behave identically on ARM64.

For C#, CodeQL supports multiple build modes, including none, autobuild, and manual. The none mode can create the CodeQL database without compiling the application, while autobuild and manual involve the project's build process.

Why Run CodeQL on ARM64?

ARM64 runners can make sense when your development and deployment environments already use ARM64.

For example, a team may have:

  • ARM64-based development machines

  • ARM64 containers

  • ARM64 Kubernetes nodes

  • ARM-based cloud infrastructure

  • Native ARM64 .NET workloads

Running security analysis on the same architecture can expose build and dependency problems that an x64-only CI pipeline may not catch.

There is also a practical CI benefit. GitHub provides Linux ARM64 hosted runner labels such as:

runs-on: ubuntu-24.04-arm

ARM64 Linux runners are also available as self-hosted runners. GitHub currently lists ARM64 support for Linux, macOS, and Windows self-hosted runners. (GitHub Docs)

How CodeQL Analyzes C#

CodeQL treats C# as a supported compiled language.

At a high level, the process is:

C# source code
      |
      v
CodeQL database
      |
      v
CodeQL queries
      |
      v
Security results
      |
      v
Code scanning alerts

The database represents the structure of the source code so that CodeQL queries can identify security problems and other defects.

For C#, CodeQL supports:

  • none

  • autobuild

  • manual

The correct choice depends on how the application is built and how much control you need over the analysis.

A Basic ARM64 CodeQL Workflow

A simple GitHub Actions workflow can use an ARM64 Linux runner:

name: CodeQL

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  analyze:
    name: Analyze C#
    runs-on: ubuntu-24.04-arm

    permissions:
      security-events: write
      packages: read
      actions: read
      contents: read

    strategy:
      fail-fast: false
      matrix:
        language:
          - csharp

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}

      - name: Build
        run: dotnet build --configuration Release --no-restore

      - name: Perform CodeQL analysis
        uses: github/codeql-action/analyze@v4

The exact action versions should be aligned with the versions approved for your organization's workflows.

The important part for ARM64 is the runner selection:

runs-on: ubuntu-24.04-arm

That causes the job to execute on a Linux ARM64 environment rather than the normal x64 Linux runner.

Use none Build Mode When Appropriate

One of the useful options for C# is the none build mode.

- name: Initialize CodeQL
  uses: github/codeql-action/init@v4
  with:
    languages: csharp
    build-mode: none

With none, CodeQL creates its database directly from the source without requiring a normal application build.

This can simplify the workflow when your goal is source analysis and the repository does not need compilation for the CodeQL database.

It can also reduce the number of architecture-specific build dependencies in the workflow.

However, none does not mean that every project should use it. If your application contains generated code or relies on build steps that affect the source CodeQL sees, a build-based approach may provide more complete analysis.

When to Use Autobuild

autobuild lets CodeQL determine how the C# project should be built.

For a standard .NET project, the workflow can use:

- name: Initialize CodeQL
  uses: github/codeql-action/init@v4
  with:
    languages: csharp
    build-mode: autobuild

- name: Autobuild
  uses: github/codeql-action/autobuild@v4

- name: Analyze
  uses: github/codeql-action/analyze@v4

For C# on Linux and macOS, CodeQL's build detection can look for a .sln or .csproj and invoke dotnet build. It can also detect build scripts in the repository. (GitHub Docs)

Autobuild is convenient, but it should not be treated as magic. Complex repositories can have multiple solutions, custom build scripts, generated projects, private package feeds, or special build configuration.

In those cases, a manual build is often easier to control.

Using a Manual Build

A manual build gives the workflow explicit control over what CodeQL analyzes.

For example:

- name: Initialize CodeQL
  uses: github/codeql-action/init@v4
  with:
    languages: csharp
    build-mode: manual

- name: Restore
  run: dotnet restore

- name: Build
  run: dotnet build --configuration Release --no-restore

- name: Analyze
  uses: github/codeql-action/analyze@v4

This approach is useful when the repository has a predictable build process.

You can also build a specific solution:

- name: Build application
  run: dotnet build src/MyApplication.sln --configuration Release

That prevents unrelated projects in a large repository from becoming part of the analysis.

ARM64 Runner Requirements

The runner architecture is only one part of the setup.

For a C# analysis job, make sure the ARM64 runner has the required .NET SDK and other project dependencies.

A self-hosted runner gives you control over the environment, but that also means you are responsible for maintaining it.

Check the architecture during troubleshooting:

uname -m

A Linux ARM64 machine should report:

aarch64

Then verify the .NET installation:

dotnet --info

You should confirm that the SDK version used by the repository is installed and that the expected architecture is being used.

For projects that use global.json, verify that the requested SDK is available on the ARM64 runner.

Private NuGet Packages Need Special Attention

C# applications frequently restore dependencies from private package registries.

A CodeQL workflow can fail before analysis even starts if the ARM64 runner cannot authenticate with the package source.

For example:

- name: Configure NuGet
  run: |
    dotnet nuget add source \
      "$PACKAGE_SOURCE" \
      --name private-feed \
      --username "$PACKAGE_USER" \
      --password "$PACKAGE_TOKEN" \
      --store-password-in-clear-text

The credentials should come from GitHub Actions secrets or another approved credential mechanism.

Do not place package credentials directly in the workflow file.

If the project can restore all dependencies from public packages, this problem is simpler. Private feeds need to be available from the ARM64 environment and compatible with the authentication mechanism used by the workflow.

Watch for ARM64-Specific Dependencies

A project may compile successfully on x64 but fail on ARM64 because of a native dependency.

Common examples include:

  • Native database libraries

  • Image processing libraries

  • Cryptography libraries

  • Native compression libraries

  • Custom P/Invoke dependencies

  • Native NuGet packages

  • Tools distributed only for x64

This is one reason ARM64 CodeQL jobs can be useful even when the primary goal is security scanning.

If the workflow uses autobuild or manual build mode, the application build can expose architecture-specific problems.

For source-only analysis with none, those native dependencies may not be needed for the CodeQL database.

Check the Linux Distribution

CodeQL has an important Linux compatibility requirement.

The CodeQL CLI is currently not compatible with non-glibc Linux distributions such as Alpine Linux, which uses musl by default.

This matters when building custom containers for CodeQL.

For example, a lightweight ARM64 Alpine container may look attractive because of its small size, but it is not a suitable default environment for the CodeQL CLI.

Use a supported glibc-based Linux environment for the analysis job.

Resource Planning

CodeQL analysis can require more resources than a normal compilation.

The recommended resources depend on the size of the codebase. GitHub's current guidance starts at 8 GB RAM and 2 CPU cores for small codebases, with larger projects requiring substantially more memory and CPU. At least 14 GB of disk space is recommended for CodeQL analysis.

For an ARM64 self-hosted runner, do not provision the machine based only on the application's normal build requirements.

A runner that is sufficient for:

dotnet build

may not provide enough resources for:

dotnet build
+
CodeQL database generation
+
CodeQL query analysis

Monitor memory and disk usage when introducing CodeQL to an existing ARM64 CI environment.

Common Problems and Troubleshooting

CodeQL Starts but the Build Fails

First verify the architecture:

uname -m

Then check:

dotnet --info

Look for native dependencies that are available on x64 but missing on ARM64.

Package Restore Fails

Check the configured NuGet sources:

dotnet nuget list source

Then verify that the ARM64 runner can authenticate with private feeds.

CodeQL Cannot Run in the Container

Check whether the container uses glibc.

If the environment is based on Alpine Linux, move the CodeQL execution to a compatible Linux distribution.

Autobuild Selects the Wrong Project

Use manual build mode and explicitly specify the solution or project:

- name: Build
  run: dotnet build src/MyApplication.sln --configuration Release

This is usually easier to maintain than trying to make automatic project detection handle a complicated repository.

Analysis Runs Out of Memory

Check the runner's available memory and disk space.

For larger repositories, use a runner with more resources rather than adding random workflow changes. CodeQL analysis is resource-sensitive, and GitHub's recommended hardware scales with codebase size.

none vs autobuild vs manual

Build mode

Best suited for

Main advantage

Main concern

none

Straightforward source analysis

No application build required

May not fit projects that need build-generated information

autobuild

Standard .NET repositories

Minimal workflow configuration

Less control over complex builds

manual

Complex or customized builds

Full control over the build

More workflow maintenance

There is no universal best mode.

Start with the simplest mode that gives your repository complete enough analysis. Move to a manual build when the repository's build process requires explicit configuration.

Best Practices for ARM64 CodeQL

Keep the CodeQL workflow close to the same build environment used by the application.

Use these practices:

  1. Verify the runner architecture. Confirm that the job is actually running on ARM64.

  2. Pin the .NET SDK when required. If the repository uses global.json, make sure the requested SDK exists on the ARM64 runner.

  3. Choose the build mode deliberately. Do not use autobuild simply because it requires less YAML.

  4. Test native dependencies. ARM64 can expose packages and tools that do not support the target architecture.

  5. Use supported Linux environments. Avoid building the CodeQL environment around unsupported musl-based distributions.

  6. Provide enough memory and disk. CodeQL resource requirements can be much higher than those of a normal .NET build.

  7. Keep private package access explicit. Make sure the runner can authenticate to every feed required by the project.

  8. Analyze the same projects you build. A successful CodeQL run is more useful when the workflow covers the code that actually ships.

Conclusion

Running CodeQL for C# on Linux ARM64 is mainly an exercise in getting the CI environment right.

The CodeQL analysis itself is not limited to x64. C# is a supported CodeQL language, and GitHub provides Linux ARM64 runners that can be selected directly in GitHub Actions.

The areas that deserve the most attention are the .NET SDK, native dependencies, private package feeds, Linux distribution, CodeQL build mode, and runner resources.

For a simple repository, none or autobuild may be enough. For a larger .NET solution with custom build steps, a manual build gives you much better control over what CodeQL analyzes.

The safest approach is to treat the ARM64 runner as a real build environment, not simply as a different machine type. Once the application can restore and build reliably on ARM64, CodeQL can become another step in that same security pipeline.