A working AWS pipeline is build → test → scan → push to ECR → deploy to ECS, EKS, or Lambda, with environments, approvals, secrets via OIDC, and a rollback that actually works. This page walks the real options (GitHub Actions, CodePipeline/CodeBuild, GitLab CI, Jenkins, Argo CD), the reference architecture, the decisions that matter, and how a vetted AWS partner builds it for you — often AWS-funded if you qualify for credits.
CI/CD is two things people often conflate. Continuous Integration is "every commit is built, tested, and scanned automatically." Continuous Delivery/Deployment is "every change that passes can be released to an environment safely, on demand or automatically." On AWS, the moving parts are well understood; the difference between a pipeline that helps and one that bites you is in the details below.
A good pipeline is fast (a developer gets a pass/fail signal in minutes, not after a coffee break), reproducible (the same commit produces the same artifact every time — you build the container image once and promote that exact image through environments, you do not rebuild per environment), and safe (a bad deploy is caught before it reaches production, or rolled back automatically within seconds when it does).
It is also auditable and least-privilege. Every deploy is traceable to a commit and an actor; the pipeline assumes a narrowly-scoped IAM role rather than holding god-mode credentials; nothing has a static AWS access key sitting in a CI secret. In 2026, long-lived AWS_ACCESS_KEY_ID values in CI are a code smell — OIDC federation removes them entirely, and we treat their presence as a finding.
The honest framing for this page: the tooling is genuinely commoditized. GitHub Actions, GitLab CI, CodePipeline, Jenkins, and Argo CD can all ship code to AWS reliably. What is not commoditized is the surrounding design — environment promotion, approval gates, ephemeral preview environments, the blue-green or canary rollout, secrets handling, infrastructure-as-code in the same flow, and a rollback path you have actually tested. That is the work. That is also exactly the work a good AWS partner does for you in a week or two.
There is no single right answer — the right tool depends on where your code lives, how much you want inside the AWS IAM boundary, and whether you are deploying to Kubernetes. Here is how the five real options actually differ.
Read these as archetypes, not religion. Plenty of teams run GitHub Actions for build-and-test and Argo CD for the Kubernetes deploy, or CodeBuild as a compute backend behind a GitHub-triggered workflow. Mixing is normal.
Best when: your code is on GitHub and you want the pipeline next to the code. Authenticate to AWS with the official aws-actions/configure-aws-credentials action over OIDC — no stored keys. Huge marketplace of actions; YAML workflows live in .github/workflows.
Watch for: sprawl (dozens of unpinned third-party actions are a supply-chain risk — pin to a commit SHA), and runner costs at scale (consider self-hosted runners on EC2/Fargate for heavy build minutes or for jobs that need VPC access to private resources).
Best when: you are on GitLab (self-managed or SaaS) and want source, CI, registry, and security scanning in one product. .gitlab-ci.yml defines stages; GitLab also supports OIDC to AWS so you avoid static keys, and its container registry can stand in for ECR if you prefer.
Watch for: self-managed GitLab runners are infrastructure you now own (patching, scaling). The built-in SAST/dependency/container scanning is convenient but tiered by license — confirm what your plan includes before relying on it as your only scan.
Best when: you want the pipeline, build compute, and deploy to live entirely inside your AWS account and IAM boundary — no third-party CI touching your environment. CodePipeline orchestrates stages; CodeBuild runs the build via a buildspec.yml; CodeDeploy handles ECS/Lambda/EC2 deploys (including native blue-green and canary). CodeConnections links GitHub/GitLab as a source.
Watch for: the developer experience is more verbose than GitHub Actions, and the per-pipeline/per-action billing model means you should design pipelines deliberately rather than spawning dozens. Strong fit for regulated teams and for shops standardizing on AWS-native tooling. (Note: AWS continues to evolve this family — CodeCommit is effectively legacy for new repos; use an external Git host plus CodeConnections.)
Best when: you have an existing Jenkins estate, mature pipeline-as-code (Jenkinsfile), and plugins your team relies on. It is maximally flexible and runs anywhere.
Watch for: Jenkins is a server (or fleet) you operate — controllers, agents, plugin upgrades, and the security hygiene that comes with it. For a greenfield AWS project in 2026, most teams pick GitHub Actions or CodePipeline over standing up Jenkins. Keep Jenkins when the migration cost outweighs the benefit; do not adopt it fresh without a specific reason.
Best when: you run on Amazon EKS and want declarative, pull-based delivery: Git is the source of truth for cluster state, and Argo CD continuously reconciles the cluster to match the repo. It pairs with a CI tool (GitHub Actions/GitLab CI build the image and bump the manifest) rather than replacing it — CI builds, GitOps deploys.
Watch for: it is Kubernetes-specific. If you are on ECS or Lambda, Argo CD is not your tool. On EKS it is excellent, and it makes progressive delivery (with Argo Rollouts) and drift detection clean — but it is one more platform to run and secure.
Here is a concrete, tool-agnostic reference for a containerized service on AWS. The same six stages apply whether the orchestrator is GitHub Actions, GitLab CI, or CodePipeline; only the syntax changes. Build the artifact once; promote that artifact.
The unit of promotion is an immutable container image tagged with the commit SHA (e.g. :git-9f3a1c2), stored in Amazon ECR. You do not rebuild for staging and again for production — you build once, and the exact image that passed tests in staging is the image that runs in production. This single decision eliminates a whole class of "it worked in staging" failures.
The deploy target shapes stage 5 the most. ECS on Fargate is the lowest-operational-overhead path — no nodes to manage, native CodeDeploy blue-green, and a registered task definition per release. EKS gives you full Kubernetes (and the GitOps/Argo CD pattern) at the cost of running a cluster. Lambda deploys are function-and-alias based with weighted-alias canaries via CodeDeploy — ideal for event-driven and bursty workloads. Most early-stage product teams we route are best served by ECS Fargate; the team graduates to EKS when Kubernetes-specific needs (complex networking, operators, multi-tenant platform) actually appear.
Build the image once, tag it with the commit SHA, and promote that exact artifact through every environment. Rebuilding per environment is the single most common source of "passed in staging, broke in prod." If you take one thing from this page, take this.
A pipeline is only as good as the path a change takes from merge to production. Three things define that path: how many environments you promote through, where the human approval sits, and whether every pull request gets its own throwaway environment to test in.
A sane default is three persistent environments — dev, staging, and production — ideally in separate AWS accounts under AWS Organizations, so a mistake in dev cannot touch production data or quotas. The same image flows dev → staging → production. Promotion to production is the point where you usually insert a manual approval gate (a required reviewer in GitHub Actions environments, a when: manual job in GitLab, or a manual-approval action in CodePipeline). Lower environments deploy automatically; production deploys on approval — or fully automatically once you trust your test suite and rollback enough to practice continuous deployment.
Ephemeral / preview environments are the high-leverage upgrade. On each pull request, the pipeline spins up a short-lived, fully-isolated copy of the app (its own ECS service or Kubernetes namespace, its own URL, often a seeded throwaway database) so reviewers and QA can click through the actual change before it merges. When the PR closes, the environment is torn down automatically so you are not paying for it. This is straightforward to wire up with IaC (each PR gets a parameterized stack) and it is one of the biggest quality-of-life wins a partner can hand a product team.
The governance layer around all of this is worth getting right once: branch protection (no direct pushes to main), required status checks (build + test + scan must pass to merge), required reviewers, and an environment-protection rule so that the production deploy role can only be assumed by an approved workflow on the main branch. These are cheap to set up and they are what auditors and enterprise customers ask about.
How you shift traffic to the new version is where outages are prevented or caused. The three patterns — rolling, blue-green, and canary — trade off speed, blast radius, and infrastructure cost. AWS has native support for all three.
Rolling update replaces instances/tasks a few at a time behind the load balancer. It is the simplest and cheapest (no duplicate fleet), and it is the ECS/EKS default. The downside: during the roll, both old and new versions serve traffic, and a bad version is live for some users before you notice — so rolling depends heavily on good health checks.
Blue-green stands up a complete parallel "green" environment alongside the live "blue" one, runs validation against green, then flips traffic over at the load balancer in one move. Rollback is instant — you flip back to blue, which is still running. AWS CodeDeploy does this natively for ECS and Lambda, and it can hold the old version warm for a defined window before terminating it. The cost is briefly running two full environments.
Canary shifts a small slice of traffic (say 10%) to the new version, watches metrics and alarms for a few minutes, then shifts the rest if everything looks healthy — or rolls back automatically if a CloudWatch alarm trips. CodeDeploy ships predefined canary configurations (e.g. "10% for 5 minutes, then 100%"); for Kubernetes, Argo Rollouts gives you metric-gated canaries. Canary is the safest pattern for high-traffic production services because a bad release only ever touches a fraction of users, briefly.
The practical recommendation: rolling for dev/staging, blue-green or canary for production. Wire the production rollout to gate on real signals — error rate, latency, and a synthetic smoke test — so the system itself rolls back without waiting for a human at 3 a.m.
| Strategy | How traffic shifts | Rollback | Extra cost | Native AWS support |
|---|---|---|---|---|
| Rolling | Replace a few tasks at a time | Roll back forward (re-deploy old) | None | ECS / EKS default |
| Blue-green | Validate green, flip 100% at the LB | Instant — flip back to blue | Two full envs briefly | CodeDeploy (ECS, Lambda) |
| Canary | Small % first, then the rest if healthy | Auto on alarm; only a slice exposed | Small (extra version) | CodeDeploy + Argo Rollouts |
These three are where most homegrown pipelines are weakest — and where a partner engagement pays for itself. Get authentication, infrastructure, and rollback right and the rest of the pipeline is comparatively easy.
There are two distinct secret problems. First, how the pipeline authenticates to AWS: use OIDC federation. GitHub Actions, GitLab CI, and other CI systems can present a short-lived OIDC token that your AWS account trusts (via an IAM OIDC identity provider and a role with a scoped trust policy), so the workflow assumes a narrowly-permissioned role for the duration of the job. No AWS_ACCESS_KEY_ID, no key rotation, nothing to leak. Scope the trust policy to a specific repo, branch, and environment.
Second, secrets the application needs at runtime (database URLs, API keys, signing keys): store them in AWS Secrets Manager (or SSM Parameter Store for simpler config), encrypted with KMS, and inject them into ECS task definitions / EKS pods / Lambda at deploy time — never bake them into the image, never echo them in CI logs. Rotate via Secrets Manager. The pipeline reads only the secret ARNs it is permitted to, governed by the same scoped IAM role.
The pipeline should not just deploy your app — it should manage the infrastructure the app runs on, as code, in the same reviewed flow. Use Terraform (HashiCorp, now BSL-licensed), OpenTofu (the open-source fork of Terraform), AWS CDK, CloudFormation, or Pulumi. The pattern: a plan on the pull request (so reviewers see exactly what will change in AWS), and an apply on merge, gated behind the same approval as a production deploy.
Treat IaC like application code: a remote state backend (S3 + DynamoDB lock, or OpenTofu/Terraform Cloud) so state is shared and locked; plan output posted to the PR; policy-as-code (OPA/Conftest, or Checkov) to block non-compliant changes before apply; and a clear separation between the "platform" repo (VPC, accounts, clusters) and per-service infra. This is what turns "someone clicked around the console" into a reviewable, repeatable, auditable system.
Every deploy strategy above implies a rollback path, but a rollback path you have never exercised is a hope, not a plan. The dependable patterns: with blue-green, flip back to the still-running previous version (seconds); with canary, let the CloudWatch alarm trigger CodeDeploy's automatic rollback before most users are affected; with rolling, keep the previous task definition / image so you can redeploy the last-known-good immediately. Because you promoted an immutable SHA-tagged image, "roll back" is just "redeploy the previous tag" — clean and unambiguous.
Database migrations are the asterisk. App rollback is easy; schema rollback is not. The discipline is to make migrations backward-compatible (expand-then-contract: add the new column, deploy code that writes both, backfill, then later remove the old) so the previous app version still runs against the new schema. A good partner bakes this convention into your pipeline and your migration tooling rather than leaving it to chance.
The patterns that consistently separate pipelines that help from pipelines that hurt. None of these are exotic; all of them are skipped under deadline pressure, and all of them are cheap to fix early and expensive to retrofit late.
Do these:
Avoid these (the recurring pitfalls): long-lived AWS keys stored in CI (replace with OIDC); a single god-mode IAM role the whole pipeline shares; rebuilding the image separately for each environment; "deploy" being a hard replace with no health gate and no rollback; secrets baked into images or printed in build logs; manual terraform apply from someone's laptop with state on their disk; click-ops drift where the console no longer matches the code; an unpinned forest of third-party CI actions you have never reviewed; and a rollback procedure that exists only in a wiki page nobody has run. Each of these is a familiar incident waiting to happen, and each is exactly the kind of thing a vetted partner remediates as part of building the pipeline.
You can build everything above yourself; this page gives you the map. But most teams searching "ci/cd aws" do not actually want to spend three weeks becoming pipeline experts — they want a production-grade pipeline shipped, correctly, so the team can get back to the product. That is what CloudRoute routes you to.
CloudRoute matches you to a vetted AWS partner who builds the pipeline end to end: the CI/CD itself (GitHub Actions, GitLab CI, or CodePipeline — whichever fits your stack), OIDC authentication, the ECR + ECS/EKS/Lambda deploy, blue-green or canary rollout, secrets via Secrets Manager, the infrastructure as code, ephemeral preview environments, and a rollback path they hand over tested. You get the work done by people who do this for a living, without running a hiring loop or vetting agencies yourself.
The commercial part, stated honestly: for credit-eligible companies, the partner engagement is frequently AWS-funded — the partner is paid through AWS partner-funding programs and your AWS usage during the build is covered by credits — so the customer pays $0 or low cost. If you are not credit-eligible, it is a straightforward vetted-partner referral: you still skip the hiring-and-vetting slog, you just pay the partner for the engagement directly. CloudRoute is paid a commission by the partner, not by you. We will tell you which bucket you are in up front; we do not pretend everything is free.
If you also want the AWS credits themselves — which is what funds the engagement — that runs in parallel. See the AWS credits routes (the $100K Activate Portfolio tier is the common one for funded startups) and the startup persona page below; the pipeline build and the credit application are typically filed by the same partner in the same week.
Repo access + which AWS account(s) + your deploy target (ECS / EKS / Lambda) + how hands-on you want to stay. The partner returns a working pipeline, the IaC in your repo, preview environments on PRs, and a rollback you have watched work. For credit-eligible companies, often at $0.
The four general-purpose orchestrators compared on the axes that actually drive the decision. (Argo CD is intentionally not in this table — it is a Kubernetes GitOps deployer that pairs with one of these, not a like-for-like alternative.)
| Dimension | GitHub Actions | AWS CodePipeline/CodeBuild | GitLab CI | Jenkins |
|---|---|---|---|---|
| Where it runs | GitHub-hosted or self-hosted runners | Inside your AWS account | GitLab SaaS or self-managed runners | Self-hosted server + agents |
| Config | YAML in .github/workflows | buildspec.yml + pipeline def | .gitlab-ci.yml | Jenkinsfile (Groovy) |
| AWS auth | OIDC (no stored keys) | Native IAM (in-account) | OIDC (no stored keys) | OIDC / instance role / keys |
| Native AWS deploy | Via actions + CodeDeploy | CodeDeploy: ECS / Lambda / EC2 | Via scripts + CodeDeploy | Via plugins / scripts |
| Best fit | GitHub teams, fast default | AWS-native / regulated, all in-boundary | GitLab-centric, all-in-one tool | Existing Jenkins investment |
| Ops burden on you | Low (hosted) → medium (self-hosted) | Low–medium (managed services) | Medium (runners) | High (you run the platform) |
| Greenfield 2026 pick? | Usually yes | Yes, if standardizing on AWS | Yes, if on GitLab | Rarely fresh; keep if invested |
Situation: Already on AWS, running a containerized API and a worker on ECS, but "deploys" were an engineer running scripts from their laptop with a long-lived IAM access key in a shared .env. No staging parity, no automated tests in the path, no rollback plan, and a recent bad deploy had caused a 40-minute outage. They wanted a real pipeline but had no in-house DevOps hire and could not justify one yet. They were also raising and qualified for AWS credits.
What CloudRoute did: CloudRoute routed them within a day to a US-based AWS partner with an ECS/Fargate track record. The partner replaced the static keys with GitHub Actions over OIDC, built the six-stage pipeline (build → test → Trivy + SCA scan → push to ECR → CodeDeploy blue-green to ECS → smoke test), stood up dev/staging/prod in separate accounts with a production approval gate, added per-PR ephemeral preview environments, moved all infra to Terraform with plan-on-PR, and moved app secrets into Secrets Manager. They also filed the AWS Activate Portfolio credit application in the same week.
Outcome: Pipeline live in under three weeks. Deploys went from a nerve-wracking manual chore to merge-and-watch, with automatic rollback on a failed health check. Zero long-lived AWS keys remained. Because the company was credit-eligible, the engagement was AWS-funded and the customer paid $0; CloudRoute was paid by the partner.
build window: < 3 weeks · long-lived AWS keys removed: 100% · prod rollback: blue-green, tested · cost to customer: $0 (credit-eligible)
CloudRoute routes you to a vetted AWS partner who builds your CI/CD, IaC, and deploy strategy end to end. For credit-eligible companies it is often AWS-funded — customer pays $0. Otherwise, a clean vetted-partner referral.