AWS CodeBuild
AWS CodeBuild is a fully managed continuous integration (CI — the practice of automatically compiling and testing your code every time it changes) service. You hand it your source code and a small set of instructions, and CodeBuild spins up a fresh container, runs your build, runs your tests, and produces output files (called “artifacts”). You never manage a build server, and you pay only for the compute minutes a build actually uses. This makes it the natural “build” stage inside a larger release pipeline.
When to use CodeBuild (and when not to)
Use CodeBuild when you want repeatable, on-demand builds without owning a Jenkins box or keeping a build machine running 24/7. It shines as the middle stage of an automated pipeline: source comes in, CodeBuild compiles and tests it, and the result is deployed.
Do not reach for CodeBuild if you need a build environment that stays alive between runs (it does not — see the gotcha below), or if you already have a mature self-hosted CI system you are happy with. For very long-running or GPU-heavy jobs, also compare costs against a dedicated EC2 instance (a virtual server you rent by the hour).
| Option | Managed? | Billing | Best for |
|---|---|---|---|
| CodeBuild | Yes | Per build minute | On-demand CI in an AWS pipeline |
| Self-hosted Jenkins on EC2 | No | Per running hour | Heavy customization, always-on |
| GitHub Actions | Yes | Per minute (GitHub) | Repos already on GitHub |
How a build is defined: buildspec.yml
CodeBuild reads its instructions from a file called buildspec.yml in the root of your source. This YAML file lists the commands to run in named phases. A typical Node.js build looks like this:
version: 0.2
phases:
install:
runtime-versions:
nodejs: 22
commands:
- npm ci
build:
commands:
- npm run build
- npm test
artifacts:
files:
- "**/*"
base-directory: dist
cache:
paths:
- "node_modules/**/*"
The phases run in order: install, then pre_build (optional), build, then post_build (optional). The artifacts block tells CodeBuild which files to package and ship to Amazon S3 (Simple Storage Service — AWS object storage) or pass to the next pipeline stage.
The no-persistent-workspace gotcha
Every CodeBuild run starts in a brand-new, empty container. Nothing you downloaded last time is there. If you do not configure caching, every single build re-downloads all your dependencies from scratch — which is slow and adds billable minutes.
Because there is no persistent workspace, you must opt in to caching explicitly. Add a cache block to your buildspec (shown above) and choose a cache backend on the project:
- S3 cache — stored in an S3 bucket, shared across all builds. Best for most teams.
- Local cache — kept on the build host briefly; faster but only helps back-to-back builds.
Without this, a project that takes 90 seconds with a warm cache can take 4+ minutes cold, every time.
Creating a build project (Console)
- Open the CodeBuild console and choose Create build project.
- Under Project configuration, give it a name like
my-app-build. - Under Source, pick your provider (CodeCommit, GitHub, or S3) and the repository.
- Under Environment, choose a managed image (for example, the Amazon Linux standard image), set the compute size, and select New service role so CodeBuild creates an IAM role for itself.
- Under Buildspec, leave Use a buildspec file selected (it reads
buildspec.ymlfrom your repo). - Under Artifacts, choose Amazon S3 and pick a bucket, or No artifacts if a pipeline handles output.
- Expand Additional configuration and enable Cache (Amazon S3) to avoid the cold-build problem.
- Choose Create build project, then Start build.
Creating a build project (CLI)
With AWS CLI v2, define the project in a JSON file and create it:
aws codebuild create-project \
--name my-app-build \
--source type=CODECOMMIT,location=https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-app \
--artifacts type=S3,location=my-build-artifacts-bucket \
--cache type=S3,location=my-build-artifacts-bucket/cache \
--environment type=LINUX_CONTAINER,image=aws/codebuild/amazonlinux-x86_64-standard:5.0,computeType=BUILD_GENERAL1_SMALL \
--service-role arn:aws:iam::123456789012:role/codebuild-my-app-build-role
Then trigger a build:
aws codebuild start-build --project-name my-app-build
Output:
{
"build": {
"id": "my-app-build:7f3c1a2b-9d4e-4f6a-8b2c-0a1b2c3d4e5f",
"buildStatus": "IN_PROGRESS",
"projectName": "my-app-build",
"currentPhase": "QUEUED"
}
}
The IAM service role does the work, not you
This is the second common trap. When CodeBuild runs, it acts as its own IAM (Identity and Access Management — AWS’s permissions system) service role, not as your user. Your personal permissions are irrelevant once the build starts.
So if your build needs to read source artifacts from S3, push a Docker image to Amazon ECR (Elastic Container Registry — AWS’s private image store), or read a secret, those permissions must be attached to the CodeBuild service role. A build that fails with AccessDenied is almost always a missing permission on this role, not on your account.
aws iam attach-role-policy \
--role-name codebuild-my-app-build-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
Grant the service role only what the build needs. A build role with broad admin access is a real security risk, because anyone who can edit
buildspec.ymlcan then run arbitrary AWS commands with those permissions.
Cost note
CodeBuild bills per build minute by compute size. As a rough 2026 guide, the smallest Linux tier (BUILD_GENERAL1_SMALL) costs about $0.005 per minute, so a 3-minute build is roughly 1.5 cents. There is a monthly free tier of 100 build minutes on that small tier. The cheapest way to cut the bill is good caching — fewer minutes per build means lower cost directly.
Best Practices
- Always configure an S3 or local cache and a matching
cacheblock inbuildspec.yml— cold builds waste time and money. - Scope the CodeBuild service role to the minimum permissions the build actually needs (least privilege).
- Pin
runtime-versionsin your buildspec so builds are reproducible and do not silently change when AWS updates default versions. - Store secrets in AWS Secrets Manager or Systems Manager Parameter Store and reference them, never hard-code them in the buildspec.
- Keep build logs in Amazon CloudWatch Logs (turned on by default) to debug failures quickly.
- Use a small compute size by default and scale up only for builds that genuinely need it.