Appearance
AWS compute for our GitHub Actions runners
Assessed 2026-09-23. The question: keep the entire GitHub Actions flow exactly as built (same workflows, same gates, same deploy controls), and use AWS only to supply the compute the jobs run on, so GitHub's 2,000-minute quota stops being the constraint. Can that run at a hard ₹0/month?
This is not a move to AWS-native CI. CodePipeline and CodeBuild-as-a-pipeline would replace Actions, and they are out of scope (see What is out of scope).
Prices are USD from the AWS Price List API for Mumbai (ap-south-1) unless marked us-east-1. Rupee figures assume ≈ ₹88 / $ (an assumption, not a sourced rate), and AWS India adds 18% GST to every charge. Anything not confirmed on an official page is marked UNVERIFIED.
CORRECTION 2026-09-23: the workload figures on this page are overstated
What was wrong. They counted 818 quota-blocked jobs (jobs GitHub refused without running, which bill nothing) at one minute each. August's executed usage was 1,381 Linux + 65 macOS minutes up to the 11 August block, not 2,409 + 90. The measured breakdown is in GitHub Actions usage forensics.
What stands. The conclusions don't change: ₹0 only during the ≤ 6-month Free plan, and no ₹0 macOS. AWS cost estimates here are, if anything, high.
Why AWS may be unnecessary. That page found the quota burn is a configuration problem (a failing nightly schedule and Dependabot CI), fixable without new compute.
VERDICT
AWS can supply the compute, but only for a limited period at ₹0.
- For up to 6 months: ₹0, guaranteed. A new account on AWS's Free plan cannot be charged; usage draws down $100 of credits (up to $200 with activities). At our measured volume, CodeBuild runners fit inside that for the whole 6-month window.
- After month 6: not ₹0. The Free plan ends and the account closes unless upgraded to Paid. On Paid, the same compute costs about $12–24/month (≈ ₹1,250–2,500 incl. GST) at August's volume.
- macOS: never ₹0 on AWS. Mac runs only on Dedicated Hosts with a 24-hour minimum ($15–29/day), so the iOS job stays on GitHub-hosted runners.
- What changes in the repo: only each job's
runs-on:line, which is unavoidable for any non-GitHub machine. Workflows, gates, environments and deploy rules stay as they are.
| Key figure | Value |
|---|---|
| GitHub charge for jobs on our own (self-hosted) runners, AWS included | $0, and those minutes don't count against the 2,000 |
| Linux compute used in August (last complete month) | 2,409 min (≈ 40 hours) |
| Paying CodeBuild for all of it | $12 (general1.small, 4 GB) to $24 (general1.medium, 8 GB) |
| Free-plan runway at that rate | 6 months fully covered with $200 credits; 4–6 months with $100 |
| GitHub quota left in use after moving Linux jobs | ≈ 930 min/month (iOS at 10×, plus deploys), inside 2,000 |
How AWS compute plugs into our existing Actions
GitHub Actions keeps orchestrating everything. A job simply names a different machine in runs-on, and GitHub hands it to that machine. GitHub bills nothing for self-hosted runners and their minutes don't come out of the 2,000 (billing docs). Every AWS option below counts as self-hosted.
| AWS compute option | How the job gets there | Pay for | Fits our jobs |
|---|---|---|---|
| CodeBuild-hosted runner (recommended) | CodeBuild listens for GitHub's "job queued" event and starts a fresh, single-use runner for that one job, then terminates it | build minutes only; nothing while idle; no public IP billed to us | Linux x64 and ARM, 4/8/16 GB sizes; Docker works on EC2 compute |
| EC2 instance running the GitHub runner | a VM with the runner agent installed; it polls GitHub over outbound 443 | instance hours + disk + public IPv4, whether or not a job is running | anything, sized as chosen; you patch and clean the machine |
EC2 spot autoscaling (terraform-aws-github-runner) | Lambda starts a spot VM per queued job and removes it after | spot hours + disk + IPv4 per job; Lambda/SQS/API Gateway glue | anything; built for teams with high concurrency |
Why CodeBuild-hosted runners fit best. They give us the "spin up only for the job" model without our having to build it. Each job gets a clean machine, so there is nothing to patch or clean up, and idle time costs nothing. An always-on EC2 runner pays for 730 hours a month to do about 40 hours of work.
The workflow change, made switchable. Once per job:
yaml
runs-on: ${{ vars.RUNNER_LINUX == 'aws' && format('codebuild-qrsetu-{0}-{1}', github.run_id, github.run_attempt) || 'ubuntu-latest' }}With the repository variable RUNNER_LINUX set to aws, the job runs on CodeBuild. Delete the variable and it runs on GitHub-hosted exactly as today. Switching becomes a setting, not a code change. The runner size can be pinned per job with CodeBuild's instance-size: label override.
Label format UNVERIFIED in combination
The codebuild-<project>-<run_id>-<run_attempt> form is documented, and so is the vars context in runs-on. Their combination via format() is our construction. Prove it on one job before rolling it out.
What the workload actually is
Measured from GitHub's run history: 976 workflow runs and 1,906 jobs, July to 23 Sep 2026. Each job's duration comes from its started_at/completed_at, rounded up to the whole minute per job (GitHub's billing rule). 226 jobs never started and cost nothing.
The /timing endpoint is not a measurement any more
GitHub's actions/runs/{id}/timing reported 0 billable minutes for every run. Under the new billing platform that field is simply empty, so it was not used.
| Month | Jobs | Linux min | macOS min | Quota draw (macOS ×10) | …of which Dependabot updates | Note |
|---|---|---|---|---|---|---|
| July 2026 | 326 | 1,051 | 0 | 1,051 | 88 | Incomplete. The quota ran out on 30 Jul, so earlier runs are missing from the API history. |
| August 2026 | 1,115 | 2,409 | 90 | 3,309 | 382 | The last complete month; over the 2,000 included. |
| September 1–23 | 239 | 874 | 119 | 2,064 | 291 | Watchdog and scheduled iOS disabled early in the month; still over quota. |
| Job (all months) | Runs | Avg min / run | Quota draw | Compute |
|---|---|---|---|---|
parity-native · iOS (macOS) | 37 | 5.6 | 2,090 | stays on GitHub (no ₹0 macOS on AWS) |
parity-native · Android | 63 | 15.8 | 998 | AWS, 8 GB, x86 |
| Dependabot update runs | 225 | 3.4 | 761 | GitHub's own job; whether it is billed is UNVERIFIED |
ci · e2e-web | 129 | 5.7 | 737 | AWS |
ci · workspace | 149 | 2.9 | 432 | AWS, 8 GB |
security · semgrep + gitleaks | 178 each | 1.5 / 1.0 | 447 | AWS |
payments-watchdog | 148 | 1.0 | 148 | now disabled |
backend-ci · Database (pgTAP) | 57 | 2.5 | 143 | AWS (Docker) |
ci · sonar | 31 | 4.2 | 131 | AWS, 8 GB (Docker) |
| All others (docs, card-ui-gate, env-drift, EF, grants, release-gate, deploys) | — | 1.0–4.0 | ≈ 540 | AWS, or keep deploys on GitHub |
How to read this.
- iOS is the biggest single quota consumer. 37 short runs used 2,090 minutes of quota, more than every job in
ci.ymlcombined (1,533), purely because of the 10× macOS rate. - AWS can't take that one at ₹0. The good news is that it doesn't need to. With every Linux job moved to AWS, August's GitHub usage would have been about 900 (iOS) + ~30 (deploys) ≈ 930 of 2,000.
Is it ₹0? The Free-plan runway
AWS changed its Free Tier on 15 July 2025. A new account gets $100 credit, plus up to $100 more for completing activities, and chooses a plan:
- Free plan. It cannot incur charges, because usage draws down credits.
- It ends at 6 months or when credits run out, whichever comes first.
- The account then closes, is kept 90 days, and is deleted unless upgraded.
- This is the only true hard ₹0 in AWS.
- Paid plan. Credits apply first, then pay-as-you-go. There is no hard cap.
(Free Tier plans · FAQ)
How long the credits carry our Linux jobs, at August's 2,409 minutes:
| Compute for all Linux jobs | $/month | $100 credit lasts | $200 credit lasts | ₹0 for the full 6 months? |
|---|---|---|---|---|
| CodeBuild general1.small (2 vCPU, 4 GB) at $0.005/min | 12.05 | 6 months (plan cap) | 6 months (plan cap) | yes, but 4 GB is too small for Android, typed lint and Sonar |
| CodeBuild mixed: 8 GB medium for heavy jobs, small for the rest | ≈ 18 | ≈ 5.5 months | 6 months (plan cap) | yes with $200, nearly with $100 |
| CodeBuild general1.medium (4 vCPU, 8 GB) for everything, $0.010/min | 24.09 | ≈ 4 months | 6 months (plan cap) | yes with $200 |
| EC2 m7i-flex.large runner (2 vCPU, 8 GB, free-tier type) 24×7 | ≈ 79.90 (73.55 instance + 3.65 IPv4 + 2.74 disk) | ≈ 1.3 months | ≈ 2.5 months | no |
| EC2 m7i-flex.large, stopped outside ~10 working hours/day | ≈ 34.50 | ≈ 2.9 months | ≈ 5.8 months | nearly, with $200 |
The "mixed" row assumes Android, workspace, e2e and sonar on medium. That split comes from the job table above, so read it as an estimate. EC2 figures use a 30 GB gp3 disk.
Two eligibility unknowns to settle on day one
- Is CodeBuild usable on a classic Free-plan account? AWS lists CodeBuild as available on the Free Tier in the new sign-up experience. For the classic ("advanced") sign-up, no page says so explicitly: UNVERIFIED.
- If it is not, the EC2 route is the certain one: m7i-flex.large is an explicitly free-tier-eligible type for new accounts (EC2 free tier).
- Does the Free plan apply to AWS India accounts? The FAQ excludes only China and GovCloud, so it very likely does: UNVERIFIED.
After month 6. Upgrade to Paid and the CodeBuild route costs about $12–24/month (≈ ₹1,250–2,500 incl. GST) at today's volume. Or let the account close and move the jobs elsewhere. There is no permanent ₹0 AWS compute at our size: the always-free allowance is 100 CodeBuild minutes/month, about 4% of August's Linux usage.
What AWS compute cannot do at ₹0
- macOS / iOS. AWS Mac runs only on Dedicated Hosts with a 24-hour minimum: $15.60 (M1) to $29.52 (M4) per day in us-east-1, and Mumbai offers Intel
mac1only ($27.36/day). CodeBuild Mac fleets are reserved-only, also 24 hours minimum, and not in Mumbai. Not free under any plan. - Anything permanent. The ₹0 lasts 6 months at most.
- An always-on runner also exhausts the credits within 1–3 months (see the runway table).
Keeping it at ₹0 while it lasts
On the Free plan, the plan itself is the cap: nothing can be charged until you choose to upgrade. Two things still matter.
1. Don't upgrade by accident. These actions convert the account to Paid:
- joining AWS Organizations, which, per the FAQ, also forfeits the credits;
- setting up Control Tower;
- joining the APN, or signing an enterprise agreement.
So on the Free plan there are no SCP guardrails, and none are needed.
2. Watch the credits, not a bill. A credit-burning mistake does not charge you; it shortens the runway.
| Setting | Why |
|---|---|
| AWS Budgets zero-spend budget + Free Tier usage alerts (85%) | early warning; both are free |
| CodeBuild project concurrency 1 (the default) | one job at a time bounds the burn rate |
| CodeBuild build timeout ≈ 30–45 min | a hung job can't burn hours |
| CloudWatch Logs retention 7 days | log storage otherwise grows forever |
| No VPC for the CodeBuild project | avoids NAT Gateway ($0.056/hr) |
| Secrets in SSM Parameter Store (standard), not Secrets Manager | standard parameters are free; Secrets Manager is $0.40 per secret-month |
| If EC2: a stop schedule (EventBridge + Lambda, both always-free) | idle hours are the biggest credit drain |
If you later upgrade to Paid, there is no hard cap. Budgets alert up to 8–12 hours late, and Budget Actions can only stop EC2/RDS or attach deny policies; they never delete anything. AWS's new spend limit has a $20/month minimum and isn't available on the classic sign-up. The protection on Paid is the settings above, plus a Budget Action that attaches a deny policy to the CodeBuild role when a monthly amount is reached.
India specifics
- Seller: an Indian address contracts with Amazon Web Services India Pvt Ltd.
- Billing: INR invoices, 18% GST, and a ₹2 card-verification charge that is refunded.
- KYC: CERT-In KYC is mandatory (PAN or Certificate of Incorporation, name matching exactly).
- Sign-up path: use "Sign up for AWS (advanced)" to keep Mumbai. The new sign-up experience (16 Sep 2026) puts India accounts in Sydney.
Hidden-cost risks
On the Free plan these burn credits. On Paid they bill.
| Resource | How it catches people (Mumbai) | Our rule |
|---|---|---|
| Public IPv4 / Elastic IP | $0.005/hr per address, in use or idle (≈ $3.65/mo); no free allowance for new accounts | CodeBuild avoids it; on EC2, stop the instance so the auto-assigned IP is released |
| EC2 left running | 24×7 is 730 hours; an idle runner costs the same as a busy one | CodeBuild; or a stop schedule |
| EBS volumes / snapshots | gp3 $0.0912/GB-mo even when the instance is stopped; snapshots $0.05/GB-mo | small disk; no snapshots |
| NAT Gateway | $0.056/hr (≈ $40.88/mo) + $0.056/GB. The classic runner bill shock | never; no VPC |
| CloudWatch Logs | $0.67/GB ingest beyond 5 GB; retention is forever by default | 7-day retention |
| S3 | no permanent allowance for new accounts; CodeBuild caches write here if enabled | no S3 cache |
| ECR private | $0.10/GB-mo after a 500 MB first-year allowance | use public images |
| Data transfer | $0.1093/GB beyond 100 GB/month out | npm and Docker pulls are inbound (free); fine at our size |
| CodeBuild reserved or Mac fleets | bill while idle (60-min / 24-hour minimums) | on-demand only |
| Security trials (GuardDuty, Config, Security Hub) | free trials that convert | don't enable |
| GitHub side | the $0.002/min self-hosted fee was announced for 1 Mar 2026 and postponed, not cancelled | small at our volume if it returns; watch the changelog |
Setup plan
- Create the account.
- "Sign up for AWS (advanced)", Mumbai, Digious business details, CERT-In KYC.
- Choose the Free plan.
- Root MFA, no root access keys, one admin IAM user.
- Don't create or join an Organization.
- Credits. Complete the Free Tier activities (up to +$100). They double the runway.
- Alerts. Zero-spend budget, Free Tier usage alerts, and credit-balance emails.
- Connect GitHub. CodeConnections GitHub App ("AWS Connector for GitHub") on
digious-platforms/qrsetu. - Runner project.
- One CodeBuild project named
codebuild-qrsetu-style, as a GitHub Actions runner project. - Webhook on
WORKFLOW_JOB_QUEUED, Ubuntu x86-64 image,general1.mediumdefault. - No VPC, 45-min timeout, concurrency 1, 7-day log retention.
- One CodeBuild project named
- Prove it on one job before touching the rest.
- Point
release-gate(Node only, ~1 min) at AWS through thevars.RUNNER_LINUXswitch. - Read the credit balance after 48 hours.
- Point
- Move the Linux jobs one workflow at a time, cheapest first:
ci→backend-ci→security→parity-native· Android.- Compare each against its last GitHub-hosted run.
- Docker jobs (pgTAP, sonar, semgrep's
container:) need CodeBuild's EC2 compute, not Lambda.
- Keep on GitHub-hosted:
- the iOS job (macOS);
- optionally deploys (
deploy-web,deploy-prod), so production credentials and GitHub's environment branch policies stay on GitHub's machines.
- Put a date in the calendar for month 5. Decide then:
- upgrade to Paid (~₹1,250–2,500/month at today's volume), or
- move the jobs back or elsewhere before the account closes.
Beyond AWS, for completeness
GitHub doesn't care whose machine a self-hosted runner is on.
- Our own Mac mini M4 (16 GB), registered as a runner, is ₹0 permanently.
- It is also the only ₹0 macOS machine available to us, so it could take the iOS job too.
- The trade-off: it only works while that machine is on, and it depends on one person's hardware.
It needs the same runs-on switch, so it can sit alongside AWS rather than replace it.
What is out of scope
- CodePipeline, and CodeBuild triggered directly by a GitHub webhook. These replace Actions as the CI definition (gates and deploy rules would move into AWS configuration). The requirement is to keep the current flow, so they are not assessed.
- SonarQube hosting. The existing
sonarjob boots SonarQube inside the job; on an 8 GB CodeBuild runner it runs as it does today. SonarQube Cloud's free plan is not an option either way: it caps private code at 50k lines, and our scanned sources are ≈ 198k non-blank lines (our count).
Sources
- AWS Free Tier:
- plans
- FAQ
- terms (last updated 9 Jul 2025)
- EC2 free tier by account date
- CodeBuild:
- CodeConnections: connecting GitHub
- Unit prices:
- AWS Price List API bulk files for
ap-south-1(CodeBuild published 11 Sep 2026, EC2 21 Sep 2026) - VPC pricing (public IPv4, NAT)
- EC2 Mac
- AWS Price List API bulk files for
- Cost controls:
- AWS India:
- GitHub:
- billing and usage ("free for self-hosted runners")
- runner pricing
- 2026 pricing changes and postponement
- secure use of self-hosted runners
Unverified or conflicting
- CodeBuild availability on a classic Free-plan account.
- The Free plan for AWS India accounts.
- The
format()label construction. - Whether CodeBuild-runner minutes draw from the 100 always-free minutes.
- How macOS minutes draw down GitHub's quota after the 1 Jan 2026 price change (10× assumed).
- Whether Dependabot's own update runs are billed.
- The INR rate.