Self-hosted GitHub Actions runners give teams control over the operating system, installed software, network, hardware, and security configuration used by their workflows.
That control also creates another responsibility: keeping the runner software current.
GitHub self-hosted runners normally update themselves automatically. The problem appears when teams disable automatic updates, use containerized or ephemeral runners, or maintain their own runner images.
In those environments, simply knowing that a newer runner exists is not enough. You need a way to identify the installed version, determine whether that version is approaching end of life, and decide when the runner should be replaced.
The GitHub Actions REST API provides runner-version endpoints that can be used as part of that process.
Why Runner Versions Matter
The runner is the software that receives a GitHub Actions job and executes it on the machine.
A workflow depends on the runner for more than simply starting shell commands. New GitHub Actions functionality can require changes in the runner itself.
This creates a dependency:
GitHub Actions service
|
v
Runner capabilities
|
v
Workflow execution
If the runner is too old, a workflow may not be able to use newer functionality correctly.
GitHub states that when automatic updates are disabled, runners must be updated within 30 days of a new version becoming available. If a required security update is released, the runner may stop receiving jobs until it is updated.
That makes runner version management an operational concern, not just maintenance work.
Automatic Updates vs Managed Updates
Self-hosted runners automatically update by default.
For many environments, that is the simplest option.
The problem is that some environments intentionally disable automatic updates.
For example:
Runner images are built through CI.
Runners run inside containers.
Infrastructure changes require approval.
Production runners follow controlled release windows.
Security teams require software to be validated before deployment.
Organizations use immutable virtual machines.
In these environments, administrators may register a runner with automatic updates disabled:
./config.sh \
--url "$GITHUB_URL" \
--token "$RUNNER_TOKEN" \
--disableupdate
Once automatic updates are disabled, the organization becomes responsible for tracking and deploying runner updates.
What the Runner Version API Provides
GitHub provides REST API endpoints for runner-version lifecycle information.
One particularly useful endpoint returns the end-of-life schedule for a specific runner version.
At the organization level, the response includes information such as:
{
"runner_version": "2.300.0",
"runtime_deprecates_at": "2026-09-01T00:00:00Z"
}
The same type of information is available at repository and enterprise scope.
This makes it possible to build a simple internal process:
Current runner version
|
v
Query lifecycle information
|
v
Check deprecation date
|
+---- Safe -> Continue
|
+---- Approaching -> Plan update
|
+---- Deprecated -> Replace immediately
The API does not automatically upgrade your machines. It gives your automation the information required to make that decision.
Find the Runner Version First
Before building an update process, collect the versions currently deployed.
A runner can expose its version through the installed runner software.
For example, from the runner directory:
./run.sh --version
Your infrastructure inventory should record at least:
Runner name
Runner group
Operating system
Architecture
Runner version
Image version
Last update
Environment
For a larger organization, this can become a small inventory database or configuration-management record.
Example:
runner-prod-01 linux-x64 2.335.0 production
runner-prod-02 linux-x64 2.335.0 production
runner-build-01 linux-arm64 2.334.0 build
runner-win-01 win-x64 2.333.1 testing
Once versions are inventoried, lifecycle checking becomes much easier.
Querying the Version Lifecycle API
The organization-level endpoint follows this pattern:
GET /orgs/{org}/actions/runners/deprecations/{version}
The request needs appropriate authentication and organization runner-management permissions.
A simple C# client can call the endpoint like this:
using System.Net.Http.Headers;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue(
"application/vnd.github+json"));
client.DefaultRequestHeaders.Add(
"X-GitHub-Api-Version",
"2026-03-10");
var organization = "my-organization";
var runnerVersion = "2.300.0";
var response = await client.GetAsync(
$"https://api.github.com/orgs/{organization}/actions/runners/deprecations/{runnerVersion}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
The important design point is that the version is an input.
Your automation can discover the versions currently deployed and query lifecycle information for each one.
Building a Runner Health Check
A useful internal service can turn the API response into a simple status.
For example:
public sealed record RunnerLifecycle(
string RunnerVersion,
DateTimeOffset RuntimeDeprecatesAt);
public static string GetStatus(
RunnerLifecycle lifecycle,
DateTimeOffset now)
{
var remaining =
lifecycle.RuntimeDeprecatesAt - now;
if (remaining <= TimeSpan.Zero)
return "Deprecated";
if (remaining <= TimeSpan.FromDays(14))
return "Update required soon";
if (remaining <= TimeSpan.FromDays(30))
return "Plan update";
return "Current";
}
This is intentionally simple.
The goal is not to create another complicated monitoring system. The goal is to turn runner lifecycle information into an actionable signal.
Enterprise, Organization, and Repository Scope
The API provides lifecycle information at different scopes.
This is useful because runner ownership is not always organized at one level.
For example:
Enterprise
|
+-- Organization A
| |
| +-- Repository 1
| +-- Repository 2
|
+-- Organization B
|
+-- Repository 3
A centrally managed enterprise may want enterprise-level reporting.
An organization administrator may only need organization-level information.
A team managing a repository-specific runner can use the repository-level endpoint.
Join the conversation! Your thoughts help the community grow.