How GitHub Actions Is Built: CI/CD Infrastructure and the Lock-In Nobody Talks About
A technical teardown of GitHub Actions' architecture and why its real moat isn't the runners — it's owning the event graph of your entire repo.
What GitHub Actions actually is under the hood
Strip away the marketing and GitHub Actions is three systems glued together: an event bus that listens to everything happening in a repo (pushes, PRs, issue comments, releases, cron ticks), a workflow orchestrator that turns YAML into a DAG of jobs and steps, and a fleet of ephemeral VMs/containers that actually execute your code. None of those three pieces is novel in isolation. Jenkins had pipelines-as-code a decade earlier. CircleCI had container-based ephemeral runners before GitHub did. Event-driven automation is as old as webhooks.
What makes Actions distinct is that the event bus isn't bolted on from outside — it's the same internal event stream GitHub already uses to power notifications, the API, and webhooks. When you open a PR, GitHub doesn't have to ship a payload across the internet to a third-party CI service, wait for it to poll back, and reconcile state. It just appends a job to a queue the runner fleet is already watching. That's a genuine architectural advantage: lower latency, no webhook flakiness, no OAuth dance, no 'why didn't my build trigger' support tickets caused by a dropped webhook.
The runner fleet: Azure VMs, containers, and the Actions Runner Controller
GitHub-hosted runners are VMs provisioned on Azure (GitHub is owned by Microsoft, and yes, that's the whole reason the hosted tier is price-competitive — they're buying compute at Azure's internal cost, not retail cloud pricing). Each job gets a fresh VM image, baked nightly with a known set of SDKs, browsers, and tools via the actions/runner-images repo. That image-baking pipeline is itself a serious piece of infrastructure — hundreds of packages, versioned, tested, and shipped on a cadence, which is why 'ubuntu-latest' quietly works for 90% of projects without anyone configuring a Dockerfile.
For self-hosted runners, GitHub ships the Actions Runner Controller (ARC) for Kubernetes, which reconciles a CRD describing desired runner pods against actual pod count — standard Kubernetes operator pattern, nothing exotic. The clever part isn't the controller, it's the protocol between runner and server: runners poll for jobs rather than GitHub pushing to them, which means self-hosted runners work behind corporate firewalls with zero inbound ports open. That single design decision is why enterprises tolerate Actions in air-gapped-ish environments where competitors require inbound webhook access or a hosted relay.
Workflow YAML is a DSL compiler problem, not a config problem
People treat the workflow YAML file as config, but it's actually a small compiler: parsing, expression evaluation (`${{ }}` context syntax), dependency resolution between jobs via `needs`, matrix expansion that can turn five lines into fifty parallel jobs, and reusable workflow composition that behaves like function calls with inputs and secrets scoping. Getting the semantics right — what's visible to a job, when secrets get masked in logs, how matrix failures propagate — is genuinely hard distributed-systems-adjacent work, not CRUD.
This is also where most of the support burden and bug reports live. Expression contexts, secret masking edge cases, and matrix/needs interactions are the parts of Actions that still produce GitHub issues years after launch, which tells you the YAML DSL is doing more real computation than it looks like from the outside.
Technical cloneability: could you rebuild this with Cursor and a weekend?
The orchestration layer — parse YAML, build a DAG, dispatch jobs, stream logs back — is absolutely something an AI coding tool can scaffold convincingly in a day. Dagger, Earthly, Woodpecker, and a dozen open-source CI engines prove the core loop isn't protected IP. If oneprompt scored just 'can I clone the job runner and YAML parser,' Actions would land solidly cloneable.
But that's not the product people are locked into. The hard-to-clone part is the marketplace of 20,000+ community Actions, the deep auth integration (OIDC tokens scoped to a specific repo and workflow run, no stored cloud credentials needed), and the fact that Actions reads repo state — PR metadata, check runs, deployment environments — without any API round trip because it already lives inside GitHub's data model. You can clone the executor. You cannot clone 20,000 third-party maintainers who already wrote the Docker build action, the Slack notifier, the Terraform plan commenter, and keep them updated for you.
The real moat: owning the event graph, not the compute
This is the part that matters for anyone evaluating whether 'GitHub but with better CI' is a viable wedge. GitHub's moat isn't runners — runners are a commodity, AWS and every CI vendor sells the same ephemeral-container idea. The moat is that Actions sits on top of the same object graph as code review, issues, packages, and security scanning. A workflow can react to a PR label, write back a check status that blocks merge, publish to GitHub Packages, and trigger a deployment environment with required reviewers — all without an API key, because it's the same system.
A standalone CI company has to re-earn all of that context through integrations: OAuth into your repo, poll or webhook for state, authenticate again to push a status check. Every one of those integration points is a place where latency, auth expiry, or rate limits leak in. GitHub skips the integration tax because it isn't integrating with anything — it's reading its own database. That's a structural advantage, not a feature gap, and it's why CircleCI and Travis lost share to Actions even when their execution engines were technically fine.
Developer workflow lock-in: the part that actually keeps you paying
The lock-in isn't the YAML syntax — people grumble about `${{ }}` syntax constantly and migrate anyway. The lock-in is behavioral: branch protection rules that require specific named checks, deployment environments with approval gates tied to Actions workflow runs, OIDC trust relationships configured against your cloud provider pointing at a specific GitHub repo/workflow, and status checks embedded in every PR your team has merged for the past three years. Ripping Actions out means re-plumbing branch protection, re-issuing cloud trust policies, and retraining every engineer's muscle memory for 'push, see green check, merge.'
This is the pattern oneprompt flags constantly: a product can be technically cloneable at the code level while being nearly impossible to displace because the switching cost lives in your org's processes, not in the vendor's codebase. If you're evaluating a CI competitor or thinking about building one, the question isn't 'can I build a job runner' — you can, this week, with an LLM doing most of the scaffolding. The question is whether you can get a team to re-point their branch protection rules and cloud IAM trust policies at you, which is an organizational migration problem, not an engineering one.
What this means if you're sizing up a CI/CD competitor
Score it on two axes, same as everything else on oneprompt. Technical cloneability: high — DAG orchestration, container dispatch, and YAML parsing are solved problems and AI tooling shortens the build time further. Business moat: it depends entirely on distribution. If the competitor lives outside the host platform (a GitLab, a standalone CI vendor), its moat is thin and it will keep losing share to the platform that owns the repo. If it's trying to unseat GitHub Actions specifically, it's not fighting a CI engine, it's fighting an event graph, an OIDC trust network, and years of accumulated branch-protection configuration across every customer's repos. Clone the runner all you want — the moat was never the runner.
Want the same teardown for any site?
Analyze a site →