Summary:
- Learn how to build a production-ready four-stage pipeline in AWS CodePipeline covering source, build, test, and deploy stages with manual approval gates and rollback strategies.
- Discover CodePipeline V2 features including deploy spec files, pipeline-level variables, and branch filters that simplify EC2 and container deployments.
- Understand IAM role configurations, artifact flow patterns, and cross-account deployment strategies that senior engineers implement in enterprise environments.
- Apply best practices for monitoring, notifications, and cost optimization to maintain reliable CI/CD workflows at scale.
Shipping code to production without a reliable pipeline is like navigating without a compass. You might eventually reach your destination, but the journey will be full of manual errors, inconsistent deployments, and sleepless nights debugging failed releases. AWS CodePipeline eliminates this chaos by orchestrating your entire release workflow through automated stages that build, test, approve, and deploy your applications with precision.
This AWS CodePipeline tutorial walks you through creating a four-stage pipeline that mirrors what engineering teams deploy in production environments. It includes manual approval gates, rollback mechanisms, and the latest V2 features that AWS introduced to streamline modern CI/CD workflows.
The following diagram illustrates the complete architecture you will build. It shows how artifacts flow through each stage and how IAM roles govern access at every transition point.
Overview of a four-stage pipeline
A four-stage pipeline represents the minimum viable structure for production-grade CI/CD. Each stage serves a distinct purpose in the software delivery lifecycle, and understanding their interactions is essential before diving into implementation.
The source stage monitors your repository for changes and triggers the pipeline. The build stage compiles code, runs unit tests, and produces deployable artifacts. The test stage executes integration or end-to-end tests against a staging environment. Finally, the deploy stage pushes validated artifacts to production, often gated by manual approval to ensure human oversight before customer-facing changes go live.
AWS CodePipeline orchestrates these stages through a declarative model where each stage contains one or more actions. Actions execute sequentially or in parallel within a stage, and artifacts produced by one action become inputs for downstream actions. This artifact-passing mechanism relies on Amazon S3 as the intermediate storage layer, with encryption at rest using AWS KMS keys. The pipeline execution model follows an event-driven orchestrator approach. When a stage completes, the pipeline engine triggers the downstream action, securely passing the S3 artifact location and temporary IAM credentials via a job payload.
Consider the following core components that every pipeline requires:
- Service role: An IAM role that CodePipeline assumes to interact with other AWS services on your behalf.
- Artifact store: An S3 bucket where pipeline artifacts are stored between stages.
- Stage definitions: Declarative configurations specifying actions, input/output artifacts, and execution order.
- Action providers: AWS services or third-party integrations that execute specific tasks within each stage.
With this foundational understanding established, the next section guides you through configuring the source and build stages that form the pipeline’s entry point.
Setting up source and build stages
The source stage establishes connectivity between your version control system and the pipeline. AWS CodePipeline supports multiple source providers including AWS CodeCommit, GitHub, GitHub Enterprise, Bitbucket, and Amazon S3. For this tutorial, we focus on CodeCommit integration, though the principles apply universally. When configuring the source action, you specify the repository name, branch to monitor, and output artifact name that downstream stages will reference.
Configuring the source action
Navigate to the CodePipeline console and select Create pipeline. With V2 pipelines now the default, you gain access to pipeline-level variables and enhanced trigger configurations. Name your pipeline descriptively, such as “webapp-prod-pipeline,” and allow CodePipeline to create a new service role or select an existing one with appropriate permissions. The service role requires permissions to access CodeCommit, S3, CodeBuild, CodeDeploy, and any other services your pipeline invokes.
In the source stage configuration, select AWS CodeCommit as the source provider. Choose your repository and specify the branch name, typically “main” or “release.” Enable Amazon EventBridge as the detection mode rather than legacy polling, which reduces latency from minutes to seconds when commits land. The output artifact name, commonly “SourceOutput,” becomes the input reference for your build stage.
Configuring the build action with CodeBuild
The build stage transforms source code into deployable artifacts using AWS CodeBuild. Create a CodeBuild project that references a buildspec.yml file in your repository root. This file defines build phases including install, pre_build, build, and post_build commands. Each phase executes sequentially, and failures in any phase halt the pipeline with detailed logs available in CloudWatch.
A production-ready buildspec.yml typically includes dependency installation, unit test execution, artifact compilation, and output artifact specification. The artifacts section defines which files CodeBuild packages and passes to subsequent stages. For a Node.js application, this might include the compiled JavaScript, node_modules directory, and deployment configuration files.
The following diagram shows how the buildspec.yml phases execute within CodeBuild and produce artifacts for downstream consumption.
After configuring source and build stages, your pipeline can automatically compile code on every commit. The next section adds quality gates through test stages and manual approval actions that prevent untested code from reaching production.
Adding test stage and manual approval
The test stage validates that built artifacts function correctly before deployment. While unit tests typically run during the build phase, integration tests require a deployed environment to verify component interactions. This stage often deploys to a staging environment, executes test suites, and reports results back to the pipeline. Failures here halt progression, protecting production from regressions.
Implementing integration tests
Create a separate CodeBuild project dedicated to integration testing. This project’s buildspec.yml should deploy artifacts to a staging environment, wait for deployment completion, execute integration test suites using frameworks like Jest, Pytest, or Selenium, and report results. The test project receives BuildOutput as its input artifact and produces TestResults as output for audit purposes.
Consider structuring your test stage with parallel actions when test suites are independent:
- Deploy artifacts to staging environment using CodeDeploy or direct S3 sync.
- Execute API integration tests against staging endpoints.
- Run end-to-end browser tests using headless Chrome in CodeBuild.
- Generate test coverage reports and store in S3 for compliance.
Configuring manual approval actions
Manual approval actions introduce human oversight before production deployments. This gate allows release managers, QA leads, or on-call engineers to review test results, verify staging behavior, and approve or reject the release. Configure the approval action with an SNS topic to notify approvers via email or Slack integration when their review is required.
The approval action configuration includes a review URL pointing to your staging environment, comments describing what reviewers should verify, and an SNS topic ARN for notifications. Approvers receive a link to the CodePipeline console where they can approve or reject with comments. Rejected pipelines stop execution and require a new source commit to restart.
With test validation and human approval in place, the pipeline now has robust quality gates. The following section covers the deploy stage where approved artifacts reach production infrastructure.
Deploy stage including app spec file
The deploy stage pushes validated artifacts to production infrastructure using AWS CodeDeploy. CodeDeploy supports multiple compute platforms including EC2 instances, on-premises servers, Lambda functions, and Amazon ECS services. For EC2 deployments, the appspec.yml file defines deployment lifecycle hooks that execute scripts at specific phases like BeforeInstall, AfterInstall, ApplicationStart, and ValidateService.
Understanding the appspec.yml file
AWS CodeDeploy relies on the appspec.yml file, placed in the root of your application’s source code, to manage the deployment. For EC2/On-Premises compute platforms, this file maps your source files to their destinations and defines lifecycle hooks scripts that run at specific points during the deployment. The CodeDeploy agent, running on the target instances, reads this file and executes the defined commands.
The appspec.yml file supports the following lifecycle events in order:
- BeforeInstall: Commands to prepare the instance (e.g., stopping services, backing up data).
- Install: (Implicit) The CodeDeploy agent copies files from the artifact to the target locations.
- AfterInstall: Commands to configure the application or change file permissions.
- ApplicationStart: Commands to start your application services.
- ValidateService: Health check commands to verify successful deployment before moving to the next instance.
Implementing rollback and notifications
Production deployments occasionally fail despite thorough testing. Network issues, configuration drift, or unforeseen edge cases can cause applications to malfunction after deployment. Implementing robust rollback mechanisms and proactive notifications ensures rapid recovery and keeps stakeholders informed throughout the release process.
Rollback strategies for CodeDeploy
CodeDeploy supports automatic rollback when deployments fail or when CloudWatch alarms trigger. Configure your deployment group with rollback settings that specify which conditions initiate automatic rollback. Options include rolling back when deployment fails, when specified alarms enter ALARM state, or both. The rollback process redeploys the last known good revision, restoring service quickly.
For pipelines using the newer deploy spec file approach, implement rollback through pipeline design patterns:
- Store previous artifact versions in S3 with versioning enabled.
- Create a separate “rollback” pipeline triggered manually or by CloudWatch alarms.
- Use pipeline-level variables to reference specific artifact versions during rollback execution.
Configuring pipeline notifications
AWS CodePipeline integrates with AWS Chatbot and Amazon SNS to deliver notifications for pipeline state changes. Configure notification rules that alert your team when pipelines start, succeed, fail, or require approval. Notification rules support filtering by event type, allowing you to route critical failures to PagerDuty while sending success notifications to Slack channels.
With rollback and notification infrastructure established, your pipeline handles failures gracefully. The following section explores advanced V2 features that enhance pipeline flexibility and maintainability.
Advanced features in CodePipeline V2
CodePipeline V2 introduced significant enhancements that address limitations in the original pipeline model. These features enable more sophisticated CI/CD patterns without requiring custom Lambda functions or external orchestration tools. Understanding these capabilities helps you design pipelines that scale with organizational complexity.
Pipeline-level variables
Pipeline-level variables allow you to pass dynamic values between stages without hardcoding configuration. Define variables at pipeline creation time or inject them during execution through the StartPipelineExecution API. Variables support namespace scoping, enabling different stages to reference values from specific upstream actions. Common use cases include passing Git commit hashes, build numbers, or environment-specific configuration values.
Variables follow the syntax #{namespace.variable_name} within action configurations. The codepipeline namespace provides built-in variables like PipelineExecutionId, while custom namespaces capture outputs from specific actions. This mechanism eliminates the need for intermediate S3 files or Parameter Store lookups to share data between stages.
Branch filters and trigger configurations
V2 pipelines support sophisticated trigger configurations that control when pipelines execute. Branch filters allow you to specify patterns that must match the source branch name before triggering. This capability enables monorepo patterns where different pipelines handle different application components based on changed file paths or branch naming conventions.
Compute action type
The compute action type executes commands directly within the pipeline without requiring a separate CodeBuild project. This lightweight alternative suits simple tasks like file transformations, API calls, or artifact manipulation. Compute actions run in managed environments with configurable compute sizes, reducing the overhead of maintaining dedicated build projects for trivial operations.
These V2 features provide building blocks for sophisticated pipelines. The final section consolidates best practices for security, cost optimization, and operational excellence.
Best practices and cost optimization
Building a functional pipeline is the first step. Operating it efficiently at scale requires attention to security boundaries, cost management, and operational patterns. The following practices reflect lessons learned from enterprise CodePipeline deployments handling thousands of daily executions.
Security and IAM configuration
Apply least-privilege principles to all pipeline roles. The pipeline service role should only access resources required for pipeline execution. Create separate roles for CodeBuild and CodeDeploy actions with permissions scoped to their specific functions. Use IAM conditions to restrict actions to specific resources, preventing lateral movement if credentials are compromised.
For cross-account deployments, establish trust relationships between accounts using IAM roles with external ID conditions. The source account’s pipeline assumes a role in the target account to execute deployment actions. This pattern maintains security boundaries while enabling centralized pipeline management across organizational units.
Cost optimization strategies
CodePipeline pricing follows a per-pipeline model with V2 pipelines incurring charges based on action executions. Optimize costs through these approaches:
- Consolidate pipelines: Use branch filters and variables to handle multiple environments in single pipelines.
- Right-size CodeBuild: Select compute types matching actual build requirements. Avoid over-provisioning.
- Implement caching: Configure CodeBuild caching to reduce build times and compute costs.
- Clean up artifacts: Configure S3 lifecycle policies to delete old artifacts automatically.
Monitoring pipeline health through Amazon CloudWatch metrics reveals optimization opportunities. Track metrics like pipeline execution time, stage duration, and failure rates to identify bottlenecks. Set alarms on execution duration increases that might indicate infrastructure degradation or inefficient build processes.
Conclusion
Building a four-stage pipeline in AWS CodePipeline transforms chaotic manual deployments into repeatable, auditable release processes. The source, build, test, and deploy stages you configured provide the foundation for continuous delivery, while manual approval gates ensure human oversight before production changes. CodePipeline V2 features like pipeline-level variables, native compute actions, and branch filters reduce complexity that previously required custom tooling.
The architectural patterns covered here scale from startup prototypes to enterprise workloads processing thousands of daily deployments. These include cross-account deployments, automated rollback, and notification integration. As your organization matures, extend this foundation with security scanning stages, canary deployments, and multi-region failover patterns. The investment in pipeline infrastructure pays dividends through reduced deployment failures, faster recovery times, and engineering teams confident in their release processes.
Start with the four-stage model, measure its effectiveness through CloudWatch metrics, and iterate based on your team’s specific pain points. Reliable CI/CD is a continuous improvement journey.