terraform-aws-github-runner: self-hosted GitHub Actions runners on AWS spot capacity
Terraform module for scalable GitHub action runners on AWS
At a glance
- What is it?
- A Terraform module that provisions ephemeral, auto-scaling GitHub Actions runners on AWS, scaled by Lambda functions and driven by GitHub webhooks. It suits teams that already run Terraform and want runner capacity to follow job volume, and it is a poor fit for anyone who wants a runner in five minutes.
- Who is it for?
- Adopt it if you already manage AWS with Terraform, need ephemeral runners for security or cost reasons, and can own a GitHub App plus a set of Lambda functions. Do not adopt it if you want a managed runner service or a single long-lived VM, because the module's whole design assumes the AWS control plane does the scheduling.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly HCL, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 26, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What problem terraform-aws-github-runner solves, and for whom
GitHub-hosted runners bill per minute and hand you a fixed machine image. If your workflows need a GPU, an arm64 host, a specific VPC, or a preinstalled toolchain, you end up installing it on every job. Self-hosting fixes that but moves the scheduling problem to you: somebody has to start machines when jobs arrive and stop them when the queue drains.
This module is that somebody. It creates the AWS infrastructure for self-hosted, auto-scaling runners on EC2 spot instances, and according to the README it "provides the required logic to handle the lifecycle for scaling up and down using a set of AWS Lambda functions." The stated design goals are scale-to-zero when no workflows are active, ephemeral runners that are created on demand and terminated after use, and cost optimization through spot capacity. It supports Linux on x64 and arm64 plus Windows, multiple runner configurations from one deployment, and org-level or repo-level runners. Enterprise-level runners are explicitly not supported yet.
The audience is narrow and specific: platform or DevOps engineers who already describe their AWS estate in Terraform and are willing to own a GitHub App, a webhook endpoint, and several Lambda functions in exchange for control over instance type, AMI, subnet, and spend.
How the webhook, SQS queue and Lambda functions fit together
The root module wires up six submodules, and their names describe the moving parts: webhook, runners, runner_binaries, ssm, ami_housekeeper, and instance_termination_watcher. The root also declares two SQS queues, queued_builds and queued_builds_dlq, with a separate queue policy for each. That dead-letter queue is the honest admission that a job event can fail to be processed.
The flow visible from the module layout is: a GitHub App delivers workflow job events to the webhook module, which enqueues them on the queued_builds SQS queue; the runners module consumes that queue and launches ephemeral EC2 instances from the configured AMI and subnets; the runner_binaries module keeps the GitHub Actions runner agent binaries available so instances can register themselves; and the instance_termination_watcher handles the other end of the lifecycle when instances go away. The ssm module stores configuration in AWS Systems Manager Parameter Store, and ami_housekeeper manages the AMI lifecycle so old images do not accumulate.
Because ephemeral runners register, take one job, and are terminated, there is no long-lived agent to patch in place. That is the security argument in the README, and it is also why the AMI becomes the real unit of maintenance: your toolchain lives in the image, and the housekeeper module is what stops those images from piling up.
Installing the module and running a first workflow
The README does not inline installation steps. It points to the Getting Started section of the documentation site and lists five high-level tasks: set up your AWS account, create and configure a GitHub App, download or build the required lambdas, deploy the module with Terraform, then install the GitHub App on your organisation or repositories and add those repositories to the runner groups. The examples directory holds scenario-specific configurations, including base, default, ephemeral, multi-runner, multi-runner-v2, prebuilt, and lambdas-download.
The version constraints come from the root module requirements table, so pin them before anything else. Terraform must be at least 1.3.0, the AWS provider at least 6.33, and the random provider in the 3.x range. The module itself is published on the Terraform Registry as github-aws-runners/github-runner/aws.
The example files under examples/ are the intended starting point rather than a copy-paste root configuration, because the module needs a GitHub App ID, a private key, and a webhook secret supplied as variables. The README does not print those variable names in the excerpt available, so read variables.tf or the configuration documentation before filling them in. After apply, the practical check is whether a workflow job lands on an instance you provisioned: the module's own signal for that is activity on the queued_builds queue and instances appearing in the configured subnets. If jobs stay queued, the dead-letter queue is where failed events surface.
Where the module is the wrong tool
Scale-to-zero is the headline behaviour, and it is also the source of the first limitation: a cold start. The README states that runners are scaled down to zero to avoid costs when no workflows are active. Nothing in the README describes a warm pool, so the first job after an idle period waits for an instance to be launched and for the runner agent to register. For a repository with sporadic pushes, that latency is paid on every run.
Spot capacity is the second constraint. The module is built around AWS spot instances for cost reasons, and spot instances can be reclaimed. The instance_termination_watcher module exists precisely because terminations happen, but a job interrupted mid-run still fails, and workflows that cannot tolerate retries or checkpointing are a poor match.
Third, this is AWS-only by construction. The module creates SQS queues, IAM policy documents, and EC2 instances; there is no abstraction layer for another cloud. If your workloads already live on ECS or Kubernetes, the related searches around running runners there point at a different architecture, and adopting this module would mean running two schedulers.
Finally, the maintainers describe the project as maintained "on a best effort basis" and invite the community to help answer issues and review pull requests. That is a candid statement about support expectations, and it should shape how much of your CI you are willing to stake on it.
How it differs from ec2-github-runner and from Kubernetes-based runners
Machulav/ec2-github-runner is the comparison people search for, and the difference is scope. That project is a GitHub Action that starts and stops EC2 instances around a workflow, so the lifecycle is driven from inside the workflow file. This module inverts the direction: GitHub events arrive through a webhook, land on an SQS queue, and Lambda functions decide when to create instances. The practical consequence is that ec2-github-runner needs no always-on infrastructure and no GitHub App, while this module needs both, and in return it can serve many repositories and runner groups from one deployment with a shared queue and scaling policy.
Kubernetes-based runners, including the Actions Runner Controller approach, take a third position: the cluster is the scheduler and pods are the runners. That reuses capacity you already pay for and avoids EC2 launch latency, but it requires a Kubernetes cluster and gives up the spot-instance cost model and the direct EC2 instance-type control this module offers. The README's feature list is explicit that you bring your own AMI and define instance types and subnets, which is a level of hardware control a pod spec does not give you.
Maintenance, versioning and the MIT licence
The project is not archived, and the last push was on 2026-09-10. Releases are frequent and versioned: v7.11.0 landed on 2026-08-17, after v7.10.2 on 2026-08-11 and v7.10.1 on 2026-07-31. Patch releases arriving within days of each other suggest active iteration, which cuts both ways: you get fixes, and you also inherit a moving target if you track the module without pinning.
Upgrade cost is real for a module of this shape. It manages IAM policies, SQS queues, Lambda functions, and EC2 resources, so a major version bump can touch infrastructure that Terraform will want to replace. The repository carries a variables.deprecated.tf file, which tells you the maintainers rename and retire inputs over time rather than keeping every old name forever. Pin the module version in your required_providers or module block and read CHANGELOG.md before moving.
Licensing is straightforward: the project is MIT licensed, with the licence text in LICENSE.md. MIT permits commercial and private use and modification, and it requires that the copyright notice and permission notice be preserved. It provides no patent grant and no warranty, which matters if you are embedding the module in a product you distribute. That is a description of the licence terms, not legal advice; your own counsel should review anything you ship.
Editorial conclusion
Adopt it if you already manage AWS with Terraform, need ephemeral runners for security or cost reasons, and can own a GitHub App plus a set of Lambda functions. Do not adopt it if you want a managed runner service or a single long-lived VM, because the module's whole design assumes the AWS control plane does the scheduling. Before writing any HCL, verify that your Terraform and AWS provider versions satisfy the requirements table (Terraform >= 1.3.0, AWS provider >= 6.33), that your organisation can create and install a GitHub App, and that you have a place to host the Lambda binaries, since the README lists downloading or building the lambdas as a distinct setup step rather than something the module fetches for you.
Frequently asked questions
What is Terraform in AWS used for in this project?
Terraform is the deployment mechanism: the module is written in HCL and creates the AWS infrastructure for the runners, including SQS queues, IAM policy documents, Lambda functions and EC2 instances. You apply it against your AWS account rather than clicking resources together in the console.
What does a GitHub runner do?
A runner executes the jobs in a GitHub Actions workflow. This module creates self-hosted runners on AWS spot instances that are provisioned on demand and terminated after use, rather than using GitHub-hosted machines.
What is Terraform GitHub?
In this context it refers to managing GitHub Actions runner infrastructure with Terraform. The module is published on the Terraform Registry as github-aws-runners/github-runner/aws and requires Terraform 1.3.0 or later.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/github-aws-runners-terraform-aws-github-runner)