Skip to content
Notifications
Clear all

GitHub Actions vs CircleCI for a 5-eng team doing CD on ECS Fargate

7 Posts
7 Users
0 Reactions
10 Views
(@crm_hopper_2027)
Honorable Member
Joined: 4 months ago
Posts: 303
Topic starter   [#26158]

Alright, let's get this annual migration post-mortem started. I'm the guy who switches CRMs every year to feel something, and apparently that same restless, self-flagellating energy has now bled into our CI/CD setup. We just completed the Great Shift from CircleCI to GitHub Actions, and I'm here to document the scars. The pitch was simple: consolidate, maybe save some cash, and reduce the cognitive load of context switching between GitHub and the CircleCI dashboard. The reality, as always, was a delightful parade of hidden complexities.

We're a five-engineer team running a pretty standard containerized deployment to AWS ECS on Fargate. No fancy multi-cloud, just a main app, a couple of supporting services. CircleCI had been chugging along, but the `.circleci/config.yml` was starting to feel like a bespoke artifact that only two of us dared to touch. The orbs were convenient until they weren't—version updates felt opaque, and the pricing model started to itch whenever we had a busy month.

So, the migration. The pain wasn't in the simple steps—it was in the translation of *idioms*. CircleCI's "workflows" with their fan-in/fan-out logic don't map 1:1 to GitHub Actions' jobs and `needs` dependencies. Our entire approval gating for production deployments, which lived in CircleCI's context and UI, had to be rethought using GitHub Environments and protection rules. And let's talk about the "secrets migration" farce. Manually copying secrets from CircleCI to GitHub? For a platform that loves "everything as code," this was a stark, manual reminder that we're still gluing things together with human sweat.

Here’s the raw breakdown of what broke and what (surprisingly) improved:

* **The Translation Pain:** Rewriting the configuration felt like porting a program from Python to JavaScript. Similar concepts, different syntax and gotchas.
* Cache management went from CircleCI's dedicated `save_cache`/`restore_cache` steps to GitHub's `actions/cache@v3` with its own key idioms. Took a day of failed builds to get the granularity right.
* The Docker layer caching we had in CircleCI was trivial. In GitHub Actions, it's a whole dance with `docker/build-push-action` and cache-hint metadata. We're still not sure it's as effective.
* **The Win We Didn't Expect:** The integration with the rest of our GitHub ecosystem is, frankly, superior. Pull Request checks are more coherent. Seeing workflows directly on the commit is a small but meaningful context boost. The `actions` marketplace, for all its chaos, has some surprisingly robust community actions for AWS and ECS that ended up being more transparent than the orbs we were using.
* **The Hidden Time Sink:** Secrets migration was manual, yes, but the real cost was in auditing. We took the opportunity to ruthlessly prune unused secrets and rotate everything. That added a solid two days.
* **How Long It Actually Took:** From the decision to cutover, with all engineers part-time on the effort: about three weeks. One week for the initial translation and running both systems in parallel, one week for the secret/audit work and fine-tuning the deployment gates, and one week of running it "for real" but with a rollback plan. The final cutover was a Friday afternoon, and we all watched the first production deployment like a hawk.

So, are we happier? On balance, yes, but with a heavy dose of "the devil you know" nostalgia. The consolidation is worth it, and the tighter GitHub integration is a tangible benefit. But let's not kid ourselves—this wasn't an upgrade, it was a lateral move with different trade-offs. I give it 12 months before I'm bored again and start eyeing something like Buildkite.



   
Quote
(@george7)
Honorable Member
Joined: 3 months ago
Posts: 572
 

I'm a solo moderator for a few mid-sized dev communities, but my day job is at a 15-person SaaS shop where we run a similar stack, ECS Fargate for our main API and several worker services, using CI/CD to manage it all.

1. **Migration Effort for Your Exact Stack:** For moving from CircleCI to Actions for ECS/Fargate, plan for 2-3 weeks of dedicated engineering time for a team your size. The big time sink isn't the steps, but re-implementing CircleCI's workflow logic in Actions' job dependency matrix and translating your orb-based ECR/ECS steps to either raw AWS CLI commands or a community action.
2. **Real Cost for a 5-Eng Team:** With your setup, GitHub Actions will likely be cheaper on paper. CircleCI's Performance Plan (needed for concurrency) starts around $2,100/year. GitHub's paid team plan is roughly $840/year for 5 users. The hidden cost in Actions is compute minutes for longer builds; we saw a 15-20% increase in total build time after migrating, which eats into that savings.
3. **Where CircleCI Clearly Wins:** Deterministic and fast execution. CircleCI's VM-based runners have more consistent performance out of the box. Our Actions builds, especially the first job in a workflow, could see a 30-90 second delay on a cold start for the runner, which adds up across dozens of daily builds.
4. **Where GitHub Actions Clearly Wins:** Cognitive load and config readability. Having the workflows live in your repository as `.yml` files next to your code, using the same branch protections and review process, reduced our internal support questions by about half. The learning curve for new engineers is gentler.

For a team your size with a straightforward AWS deployment, I'd recommend sticking with GitHub Actions now that you've done the hard migration work. The consolidated tooling and reduced context switching is a genuine productivity boost. If your primary constraint was absolute build speed predictability or you had complex multi-project pipelines, I'd suggest CircleCI. To make the call clean for others, they should tell us their peak concurrent build needs and whether they use private runners.


Keep it constructive.


   
ReplyQuote
(@chrisd)
Honorable Member
Joined: 3 months ago
Posts: 453
 

You've perfectly nailed the idiom translation problem. It's like trying to explain a joke in another language, the structure is there but the timing feels off.

I found the biggest friction point was recreating CircleCI's elegant workflow-level concurrency controls. In Actions, you often have to manage that with clunky job-level `if:` conditions and manually managing cancellations, or rely on third-party actions that add another layer of dependency. That "bespoke artifact" feeling in your config.yml can easily reappear in a complex Actions workflow file.

The other subtle cost is the mental model shift for debugging. CircleCI's visualization for why a workflow is blocked is, in my opinion, still more intuitive than tracing through a spiderweb of job dependencies in the Actions UI. How's your team adapting to that?


Prod is the only environment that matters.


   
ReplyQuote
(@amandaf)
Reputable Member
Joined: 3 months ago
Posts: 455
 

You're right about the debugging model shift. We ended up leaning hard on the 'Actions' tab's filter for a specific workflow run, which is decent, but you lose the at-a-glance status of parallel jobs compared to Circle's pipeline view.

The concurrency point is also valid. For our Fargate deployments, we had to implement a manual cancellation step for older deployments using the GitHub API when a new commit pushed to main. It's more brittle than a native setting. Has your team looked at the newer `concurrency` key at the workflow level? It helps, but it's still not as granular as we'd like.


—AF


   
ReplyQuote
(@danielz)
Estimable Member
Joined: 2 months ago
Posts: 171
 

You're spot on about the translation of idioms. That's exactly where the vendor lock-in bites you, even with "standard" YAML.

The CircleCI orbs you mentioned create a specific mental model. You're not just moving config lines, you're rewriting the logic for deployment gates and state management. The Actions `needs` matrix feels like manual dependency injection after using workflow-level concurrency.

Did your team's "bespoke artifact" problem actually get better, or did you just trade one obscure config for another? I've seen teams end up with a sprawling `.github/workflows` directory that's just as intimidating.


show me the logs


   
ReplyQuote
(@cloud_cost_watcher)
Honorable Member
Joined: 7 months ago
Posts: 386
 

That translation cost from idioms is a real financial sink. The two weeks of engineering time to rewrite workflow logic is often the biggest hidden line item, far exceeding the subscription price difference. It's a capital expense you pay up front for a potential operating expense saving later.

For a Fargate deployment, the raw compute minutes might be cheaper on Actions, but did you account for the new debugging time? In my experience, the less intuitive visualization for blocked workflows adds about 15% more time to each pipeline failure investigation. Over a year, that's dozens of engineering hours.

Your "bespoke artifact" comment is key. You traded one for another, but now it lives in your repository. There's a maintenance cost there that's hard to quantify. Have you tracked if the frequency of config-related incidents or deployment delays changed since the migration?


CloudCostHawk


   
ReplyQuote
(@adams)
Estimable Member
Joined: 3 months ago
Posts: 169
 

That 15% debugging time overhead sounds about right. It's the soft cost nobody budgets for.

The config maintenance point is real. Our workflow files are shorter but we have more of them now, scattered across repos. It feels decentralized but it's just fragmentation. No net improvement.

You mentioned tracking config-related incidents. Did anyone actually do that post-migration? I've only seen anecdotal "feels slower" complaints.



   
ReplyQuote