AWS CodeDeploy Explained: How It Works, Deployment Types, and Rollbacks

AWS CodeDeploy is a managed deployment service that automates getting new application versions onto EC2 instances, ECS services, and Lambda functions. Instead of maintaining custom shell scripts to push code to servers, you get built-in deployment strategies, lifecycle hooks, health monitoring, and automatic rollback. CodeDeploy handles the mechanics of the release. You define what success looks like.

In a CI/CD workflow, CodeDeploy is the deployment step. It sits after a build tool like AWS CodeBuild produces an artifact, and it is often triggered by CodePipeline, which orchestrates the full chain. CodeDeploy’s job is narrow and specific: take a new revision and get it running on your target compute safely.

The main payoff is controlled releases. Rather than deploying to everything at once and hoping for the best, CodeDeploy lets you shift traffic incrementally, run validation checks at each step, and roll back automatically if something goes wrong — before a human has to intervene.

AWS CodeDeploy in simple terms

Imagine your application is running on a fleet of ten EC2 instances. You have a new version ready. Without CodeDeploy, deploying it means SSHing into each server, stopping the old application, copying new files, restarting — and if something breaks on server six, figuring out what state servers one through five are in.

🚚

Analogy

Think of CodeDeploy like a professional moving crew with a checklist. They know the order of operations, they verify each step before moving to the next, and if they find a problem, they put everything back where it was. You hand them the boxes (your deployment bundle) and the instructions (appspec.yml). They do the rest — and they will not sign off on completion until they have confirmed the new setup actually works.

For ECS and Lambda, the analogy shifts slightly. There are no servers to log into. CodeDeploy manages traffic routing instead: it starts the new version alongside the old one, waits for health checks to pass, then shifts traffic over. If error rates climb, it shifts back.

What AWS CodeDeploy actually does

Underneath the surface, every CodeDeploy deployment follows the same core responsibilities regardless of which compute platform you are using:

  • Takes a revision. A versioned deployment bundle from S3 for EC2, a task definition ARN for ECS, or a Lambda version ARN for Lambda.
  • Selects the deployment group. A named set of targets: EC2 instances with specific tags, an ECS service, or a Lambda function.
  • Reads appspec.yml. The file that describes what to copy, which hooks to run, and how traffic shifting should work.
  • Runs lifecycle hooks. Scripts or Lambda functions that validate each phase of the deployment.
  • Shifts traffic. All at once, in increments, or with a canary percentage first.
  • Monitors health. Checks that the new version is actually responding before declaring success.
  • Rolls back if needed. Automatically, based on CloudWatch alarm breaches or deployment failures.
What CodeDeploy does not do

CodeDeploy does not build artifacts, run tests, or orchestrate multi-stage pipelines. It only handles the deploy step. Building is CodeBuild’s job. Orchestrating stages is CodePipeline’s job.

What CodeDeploy can deploy

CodeDeploy supports three compute platforms. Each works differently: different artifact types, different deployment mechanics, different agent requirements.

PlatformWhat gets deployedAgent requiredDeployment styleTraffic and health
EC2 / on-premisesApplication bundle (zip, tar) from S3 or GitHubYes — daemon on each instanceIn-place or blue/greenInstance health checks; lifecycle hooks validate service
ECSNew ECS task definition revisionNoBlue/green onlyALB target group traffic shifting; ECS health checks
LambdaNew Lambda function versionNoCanary, linear, or all-at-onceAlias traffic weights; pre- and post-traffic hook functions

For EC2 deployments, the CodeDeploy agent must be installed and running on every target instance. It polls the CodeDeploy service for pending deployments and executes the appspec instructions locally. For ECS and Lambda, CodeDeploy calls the AWS APIs directly. There is nothing to install.

How AWS CodeDeploy works: end to end

A deployment does not start with CodeDeploy. It starts upstream. Here is the full sequence from artifact to production:

  1. A build artifact or new version is created. For EC2, CodeBuild produces a zip bundle and uploads it to S3. For ECS, a new container image is pushed and a new task definition revision is registered. For Lambda, a new function version is published.
  2. A deployment is triggered. This can happen manually via the AWS CLI or console, or automatically when a CodePipeline stage fires after a successful build.
  3. CodeDeploy identifies the deployment group. A deployment group is a named set of targets — EC2 instances matching specific tags, a specific ECS service, or a specific Lambda function. It also holds your deployment configuration and rollback settings.
  4. CodeDeploy reads appspec.yml. The file defines what to deploy, where to put it, and what to run at each phase. For EC2, it is bundled with the artifact. For ECS and Lambda, it lives in the deployment itself.
  5. Lifecycle hooks run. Scripts (EC2) or Lambda functions (ECS/Lambda) execute at defined checkpoints — before install, after install, before traffic shifts, after traffic shifts. Each hook must succeed before the next phase starts.
  6. Traffic shifts to the new version. For EC2 in-place, the old application is stopped and replaced. For ECS and Lambda, the load balancer or alias routes traffic to the new version according to the deployment configuration.
  7. CodeDeploy determines success or failure. Health checks pass, alarms stay quiet: the deployment succeeds. A hook fails or a CloudWatch alarm fires: the deployment fails.
  8. Rollback triggers if configured. On failure, CodeDeploy automatically restores the previous state — re-deploying the previous revision on EC2, shifting traffic back to the original task set on ECS, or updating the Lambda alias back to the previous version.
Build logs live upstream

CodeDeploy does not store build logs or test results. It is a deployment execution engine. If you need visibility into what happened before the deployment triggered, that lives in CodeBuild and CodePipeline.

The appspec.yml file

Every CodeDeploy deployment is driven by an appspec.yml file. Think of it as a contract between you and CodeDeploy: you describe what needs to happen at each stage of the deployment, and CodeDeploy executes it. Without a valid appspec.yml, the deployment will not start.

The file structure differs significantly between EC2, ECS, and Lambda. They are essentially three different file formats that share the same name.

EC2 appspec.yml

For EC2 deployments, appspec.yml lives at the root of your deployment bundle alongside your application code. It tells CodeDeploy which files to copy to which directories, and which scripts to run at each lifecycle hook.

version: 0.0
os: linux

files:
  - source: /app
    destination: /var/www/myapp

hooks:
  BeforeInstall:
    - location: scripts/before_install.sh
      timeout: 180
      runas: root

  AfterInstall:
    - location: scripts/after_install.sh
      timeout: 180
      runas: myapp-user

  ApplicationStart:
    - location: scripts/start_application.sh
      timeout: 60
      runas: myapp-user

  ValidateService:
    - location: scripts/validate_service.sh
      timeout: 120
      runas: myapp-user

The hooks run in sequence: BeforeInstall, then files are copied, then AfterInstall, then ApplicationStart, then ValidateService. If any hook script exits with a non-zero code, CodeDeploy stops and marks the deployment failed. This is why ValidateService matters: it should actually test that the application is responding, not just that the process started.

ECS appspec.yml

For ECS, appspec.yml points CodeDeploy to the new task definition and configures which container and port to route traffic to. The hooks reference Lambda function names, not shell scripts.

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "arn:aws:ecs:us-east-1:123456789012:task-definition/my-app:42"
        LoadBalancerInfo:
          ContainerName: "my-app"
          ContainerPort: 8080
        PlatformVersion: "LATEST"

Hooks:
  - BeforeAllowTraffic: "ValidateBeforeTraffic"
  - AfterAllowTraffic: "ValidateAfterTraffic"

Lambda appspec.yml

For Lambda, appspec.yml identifies the function, the alias to update, and the versions to shift between. The hooks are Lambda functions that run before and after traffic shifts, so you can validate the new version before it receives full production traffic.

version: 0.0
Resources:
  - MyFunction:
      Type: AWS::Lambda::Function
      Properties:
        Name: my-function
        Alias: production
        CurrentVersion: "arn:aws:lambda:us-east-1:123456789012:function:my-function:3"
        TargetVersion: "arn:aws:lambda:us-east-1:123456789012:function:my-function:4"

Hooks:
  - BeforeAllowTraffic: PreTrafficHookFunction
  - AfterAllowTraffic: PostTrafficHookFunction
Most common appspec.yml mistake

For EC2 deployments, appspec.yml must be at the root of your deployment bundle zip, not inside a subfolder. A file at src/appspec.yml will not be found, and the deployment will fail with a confusing error that does not clearly identify the location problem.

Deployment types and traffic shifting

The deployment configuration controls how aggressively CodeDeploy shifts traffic from the old version to the new one. The right choice depends on how much risk you are willing to take during the deployment window and how fast you need rollback to work.

In-place deployments (EC2 only)

In-place deployments update the existing instances. The old application is stopped, new code is installed, and the application is restarted on the same machine. You choose how many instances update simultaneously:

  • AllAtOnce — all instances update at the same time. Fast, but one bad deployment affects 100% of capacity immediately. Acceptable in development, dangerous in production.
  • HalfAtATime — 50% of instances update first. The rest continue serving traffic. If the first half fails, CodeDeploy stops before touching the other 50%.
  • OneAtATime — one instance at a time, the most conservative option. Slowest, but a failure only affects one instance before deployment stops.

Rollback for in-place deployments means re-running the previous revision on the same instances. It takes as long as a normal deployment because the process must run again in reverse.

Blue/green deployments

Blue/green deployments provision a new environment with the new version — new EC2 instances or a new ECS task set — validate it, then shift traffic from old (blue) to new (green). The original environment stays running until you confirm everything is healthy. Rollback is instant: shift traffic back to blue without touching anything.

For ECS, blue/green is the only option CodeDeploy offers. CodeDeploy creates a second target group with the new task set, shifts traffic using the Application Load Balancer, then terminates the old tasks after a configurable wait period. This requires two target groups even though only one serves traffic at a time.

Canary and linear traffic shifting

For ECS and Lambda, CodeDeploy supports gradual traffic shifting before committing to a full cutover. These are the most conservative production deployment strategies:

  • Canary — sends a small percentage of traffic to the new version first (for example, 10%), waits for a defined period, then shifts the remaining 90% if no alarms fire. See the canary deployments guide for a full walkthrough.
  • Linear — increases traffic to the new version by a fixed increment at fixed intervals (for example, 10% every minute until 100%). Slower than canary but provides a gradual signal over a longer window.
  • AllAtOnce — shifts all traffic immediately. Fast, but eliminates the validation window.
StrategyRisk during deploymentRollback speedBest for
AllAtOnce (in-place)High — all instances at onceSlow (re-deploy previous revision)Development environments
HalfAtATime / OneAtATimeMedium — partial fleet affectedSlow (re-deploy previous revision)EC2 production with some tolerance
Blue/green (all-at-once)Low — new env validated before cutoverInstant (shift traffic back)ECS/EC2 production
CanaryVery low — small % of traffic firstFast (remove canary traffic)High-traffic ECS or Lambda production
LinearVery low — gradual rampFast (halt and reverse traffic shift)Services needing gradual validation

EC2 lifecycle event hooks

EC2 deployments have the richest set of lifecycle hooks because CodeDeploy manages every step: stopping the old application, copying files, and starting the new version. Each hook runs a script from your deployment bundle.

HookWhen it runsCommon use
BeforeInstallBefore files are copiedStop the old application, back up data, decrypt artifacts
AfterInstallAfter files are copied, before startSet file permissions, configure the app, run database migrations
ApplicationStartAfter AfterInstallStart the application process (systemctl start myapp)
ValidateServiceAfter ApplicationStartHealth check: test the HTTP endpoint, verify the process responds

Any hook that exits with a non-zero code stops the deployment and marks it failed. For in-place deployments, this leaves the instance in an intermediate state. ValidateService is the most important hook to get right: it is the only thing standing between a “deployment completed” status and a broken application that CodeDeploy thinks is healthy.

Automatic rollback

CodeDeploy can automatically roll back a deployment if it fails or if a CloudWatch alarm fires after the deployment completes. Rollback is configured at the deployment group level, and there are two triggers:

  • Deployment failure — a lifecycle hook errors out, health checks do not pass, or instances never reach a healthy state.
  • CloudWatch alarm breach — the deployment completes, but an alarm fires shortly after. For example: the 5xx error rate spikes or latency climbs past a threshold. This catches bugs that pass pre-deployment testing but only appear under real production traffic.
# Create a deployment group with automatic rollback on failure and alarm
aws deploy create-deployment-group \
  --application-name my-app \
  --deployment-group-name prod \
  --deployment-config-name CodeDeployDefault.ECSCanary10Percent5Minutes \
  --auto-rollback-configuration \
      enabled=true,events=DEPLOYMENT_FAILURE,DEPLOYMENT_STOP_ON_ALARM \
  --alarm-configuration \
      enabled=true,alarms=[{name=my-app-5xx-error-rate}]

How rollback works differs per platform. For EC2, CodeDeploy re-runs the previous revision on the same instances, which takes as long as a normal deployment. For ECS, traffic shifts back to the original task set that was kept running during deployment: near-instant. For Lambda, the function alias is updated back to the previous version: also near-instant. See rollbacks in CodeDeploy for the full breakdown.

Rollback is inert until you configure it

Automatic rollback does not enable itself. Without configuring it in the deployment group, a bad deployment stays bad until someone notices and manually intervenes. Enable rollback on both failure and alarm from day one.

When to use AWS CodeDeploy

CodeDeploy is the right choice when you need visibility, control, and rollback capability over your deployments — not just “copy files and restart.”

  • EC2 fleets needing controlled releases. If you have multiple instances and cannot afford all of them going down simultaneously, CodeDeploy’s deployment configurations handle the orchestration. You define success; CodeDeploy handles the sequencing.
  • ECS blue/green rollouts. ECS and CodeDeploy is a mature pattern for zero-downtime container releases. It integrates cleanly with the Application Load Balancer and fits well into a full ECS CI/CD pipeline.
  • Lambda traffic shifting. Canary and linear traffic shifting for Lambda gives you gradual rollout with automatic rollback. Especially useful for functions handling payment processing, authentication, or other high-stakes paths.
  • Automatic rollback on alarm. If you have meaningful CloudWatch alarms on error rates and latency, CodeDeploy’s alarm-based rollback can catch problems and restore the previous version faster than any human can respond.
  • Audit and deployment history. CodeDeploy keeps a record of every deployment, its status, and which revision was deployed. Useful for compliance and debugging production incidents.

When not to use AWS CodeDeploy

The boundary to understand

CodeDeploy is a deployment execution tool. It is not a build tool and not a pipeline orchestrator. Picking the wrong tool for a job is usually how teams end up with overly complex setups they cannot debug.

  • You only need builds, not deployments. If your goal is compiling code, running tests, or producing Docker images, that is CodeBuild’s job. CodeDeploy does not execute build steps.
  • You need pipeline orchestration. If you need to coordinate source, build, test, approve, and deploy stages with branching logic, that is CodePipeline. CodeDeploy only handles the deploy stage.
  • Your deployment is a simple static file upload to S3. For static sites or S3-hosted assets, an S3 sync is all you need. CodeDeploy adds overhead without meaningful benefit.
  • You are already using a full deployment platform. If your team uses GitHub Actions with direct ECS or Lambda deploys, adding CodeDeploy is extra complexity unless you specifically need its traffic-shifting or rollback behavior.
  • You are deploying to Kubernetes (EKS). CodeDeploy does not support EKS. For Kubernetes deployments, use kubectl, Helm, Argo CD, or Flux instead.

CodeDeploy vs CodeBuild vs CodePipeline

These three services are frequently confused because they appear together in CI/CD setups and are often used in combination. They do completely different things.

ServiceWhat it doesInputOutput
CodeBuildBuilds artifacts: compiles code, runs tests, produces zip files or Docker imagesSource code from S3, GitHub, etc.Build artifact, Docker image
CodeDeployDeploys artifacts: gets a built version running on EC2, ECS, or Lambda safelyArtifact from S3, task definition, Lambda versionRunning application on target compute
CodePipelineOrchestrates stages: connects source, build, test, and deploy into an automated workflowSource change triggerCompleted pipeline run (success or failure)

In a typical production setup, all three work together: a commit triggers CodePipeline, which calls CodeBuild to build and test the artifact, then calls CodeDeploy to deploy it. Each service does its specific job. You can also use each independently — CodeDeploy does not require CodeBuild or CodePipeline to trigger it.

Hybrid setups are common

Many teams use GitHub Actions for build and test (CodeBuild equivalent), then call CodeDeploy for the final deployment — especially when deploying to private EC2 fleets or ECS services that need traffic-shifting behavior. See secure CI/CD pipelines for how these integrations are typically secured.

Common beginner mistakes

  1. Missing or misplaced appspec.yml. For EC2, appspec.yml must be at the root of the deployment bundle zip, not inside a subfolder. For ECS and Lambda, it must be properly referenced in the deployment definition. A missing appspec.yml causes an immediate failure with a message that does not always make the location problem obvious.
  2. No ValidateService hook. Without a validation hook, CodeDeploy considers the deployment successful as soon as the start script exits without error. The application can be running but returning 500s and CodeDeploy will not know. Always write a ValidateService script that actually tests the application endpoint.
  3. Using AllAtOnce for production EC2. AllAtOnce updates every instance simultaneously. If the new version has a critical bug, 100% of your capacity is affected at the same moment. Use HalfAtATime or OneAtATime for production, or switch to blue/green to avoid the in-place risk entirely.
  4. Not configuring automatic rollback. CodeDeploy’s rollback capability is inert until you enable it. Without automatic rollback on failure and alarm, a bad deployment stays deployed until someone notices and manually intervenes. Configure it from day one — there is no reason to skip it. See rollbacks in CodeDeploy for configuration details.
  5. Confusing CodeDeploy with CodeBuild or CodePipeline. This wastes debugging time. If deployments are not being triggered, the problem is usually in CodePipeline (the orchestrator) or the build output (CodeBuild). If the deployment itself is failing, then CodeDeploy is where to look.
  6. Forgetting agent requirements for EC2. The CodeDeploy agent must be installed and running on every target EC2 instance. A new instance that joins an Auto Scaling Group without the agent will fail every deployment. Bake the agent into your AMI or install it via user data scripts. Do not rely on installing it manually.
  7. Storing secrets in appspec.yml or deployment scripts. Lifecycle hook scripts are committed to your repository inside the deployment bundle. Use Secrets Manager or SSM Parameter Store to fetch secrets at runtime, not hardcoded values in scripts.

Frequently asked questions

What is appspec.yml in CodeDeploy?

The appspec.yml file is the instruction set for a CodeDeploy deployment. It tells CodeDeploy what to do: which files to copy (for EC2), which lifecycle hook scripts to run, and where to find the new version. For ECS deployments, it points CodeDeploy to the new task definition and configures the load balancer. For Lambda, it identifies the function, the new version, and the alias to update. Every CodeDeploy deployment requires one.

Do ECS and Lambda deployments need the CodeDeploy agent?

No. The CodeDeploy agent is only required for EC2 and on-premises deployments. It runs as a daemon on each instance and polls the CodeDeploy service for instructions. ECS and Lambda deployments work through direct API calls — CodeDeploy talks to the ECS and Lambda APIs without any agent installed on anything.

What is the difference between CodeDeploy and CodePipeline?

CodeDeploy handles the deployment step: it takes a version of your application and gets it running on EC2, ECS, or Lambda. CodePipeline is an orchestration tool that connects stages — source, build, test, deploy — into a pipeline. In a typical setup, CodePipeline triggers CodeDeploy as the final stage. CodeDeploy does not know what happened before it ran; CodePipeline coordinates the whole chain.

When should I choose blue/green over in-place?

Use blue/green when rollback speed matters, when your application cannot tolerate mixed-version requests during a deployment window, or when you are deploying to production and want to validate the new version before any real traffic hits it. In-place is simpler and cheaper but rollback is slower — it requires re-running the previous deployment on the same instances. For ECS, the choice is made for you: CodeDeploy only supports blue/green.

Can CodeDeploy roll back automatically?

Yes. You configure automatic rollback at the deployment group level. CodeDeploy can roll back on two triggers: deployment failure (a lifecycle hook errors out, or health checks never pass) and CloudWatch alarm breach (the deployment succeeds but error rate or latency spikes afterward). The alarm-based rollback is particularly useful because it catches bugs that only surface under real production traffic, not in pre-deployment validation.

Last verified: 25 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.