Skip to content
  • #github actions
  • #ci
  • #aws

How I reduce 16 mins of GitHub Continuous Integration

Choosing a budget-friendly ARM64 EC2 instance came with an unexpected cost: 20-minute CI builds. Here’s how I traced the slowdown to QEMU emulation and cut GitHub Actions build time to just 4 minutes by switching to a native ARM64 runner.

Oct 12, 2026 • 3 min read

When creating a staging environment for one of my experimental news site(https://test.lankareads.lk/) , I took a t4g.small EC2 instance with ARM64. The reason behind was simply the reduced cloud budget(I am funding my stupid ideas).Compared to the instances with x86 Architecture , ARM64 instance are more lower cost and greener I would say. Here are some of the pricing in AWS.

InstanceArchitecture / ProcessorvCPUsRAMHourly Price (USD)Monthly Price (USD)¹
t4g.smallARM64 / AWS Graviton222 GiB$0.0112$8.18
t3.smallx86-64 / Intel22 GiB$0.0224$16.35
t3a.smallx86-64 / AMD22 GiB$0.0123$8.98

¹ Monthly estimates assume 730 hours of usage.

It is somewhat saving right ?, the resources. The sole purpose of staging env was to test-out some of the features , before merging into production (That is staging 101). I am not gonna deep dive about how ARM64 architecture and instruction set is more cost-effective , compared to x86 architecture. However yesterday 3AM, I figured out my GitHub actions taking around 20 mins to complete one CI task. The idea was simple : since EC2 instance is ARM64 architecture, the docker image build needs to be ARM compatible. So in GitHub actions , ubuntu-latest is an x86 machine. To produce an ARM image there, the workflow loaded QEMU (setup-qemu-action). QEMU registers itself with the Linux kernel ,so that any ARM program started inside the build is run through an emulator, which translates each ARM instruction into x86 instructions as it goes.

Inside the emulator, The next.js web do following:

  1. npm ci unpacks and installs hundreds of packages and runs their install scripts. That's thousands of small CPU and file operations, all emulated.
  2. next build is CPU-heavy: it compiles TypeScript, bundles every page and pre-renders static pages.
  3. Node.js itself compiles JavaScript to machine code at run time. Under QEMU, that freshly compiled ARM code has to be translated again, so the work is done twice.

I was impatient like a nasty client,and my inner calling saying , Bro, you stupid moron, there is something wrong in the setup, and I was newbie to this CI part and jumped to a claude session and ask what could potentially goes wrong. Understood that conversion of x86 build to ARM64 did the mistake. so switching the github runners ubuntu-24.04-arm solves the problem and CI part ran within 4 minutes compared to, previous 20 minutes, and so other backend API was written using goLang but it does not require to change the github runner since Go Lang can compile ARM programs directly on an x86 machine without emulation. Eventually all the dots connected, and saved me from another future crisis which can go wrong,and learnt:: what we call Experience.