Building Images in CI: Automating Docker Builds in GitHub Actions
Learn how to automate Docker builds in your CI pipeline. We’ll show you how to add a build step to GitHub Actions to ensure your application is always deployable.

Previously in this course, we explored Dockerizing the Pipeline, where we learned how to execute our test suite inside a containerized environment. In this lesson, we take the next logical step: moving from merely using a container to building one as a formal part of your CI pipeline.
Building images in CI ensures that your application is packaged correctly every time you push code. It acts as a "smoke test" for your Dockerfile—if the build fails, you know immediately that your application dependencies or environment configuration are broken before you even attempt a deployment.
Automating the Docker Build Process
When we talk about the Docker build process in CI, we aren't just running docker build . locally. We need to do this in a clean, ephemeral runner. GitHub Actions provides the environment, but it is our job to instruct the runner to invoke the Docker daemon and create the image.
The most reliable way to handle this is using the docker/build-push-action. This official action is optimized for GitHub Actions, offering features like layer caching and better integration with the GitHub environment.
A Concrete Worked Example
Assuming you have already followed the Introduction to Docker: Building Your First Container Image lesson, you likely have a valid Dockerfile in your root directory.
Here is how you add a build step to your existing YAML workflow:
YAMLname: CI Pipeline on: [push] jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image uses: docker/build-push-action@v5 with: context: . push: false # We only want to verify the build, not push it yet tags: my-app:latest
Why Use docker/build-push-action?
You might wonder why we don't just use run: docker build -t my-app .. While that works, the docker/build-push-action provides:
- BuildKit support: It automatically utilizes the latest Docker features for faster, more secure builds.
- Caching: It handles the complex logic of GitHub Actions cache restoration, making your builds significantly faster by reusing layers from previous runs.
- Multi-platform support: If you ever need to build for different architectures (like ARM64 for cloud instances), this action handles it natively.
Hands-on Exercise

To verify your image creation, follow these steps:
- Update your workflow: Add the
docker/setup-buildx-actionanddocker/build-push-actionblocks to your current.github/workflows/main.ymlfile. - Commit and Push: Push your changes to GitHub.
- Observe the logs: Navigate to the "Actions" tab in your repository. Click on the latest workflow run.
- Verify: Expand the "Build Docker image" step. You should see the Docker engine pulling layers, executing your
RUNcommands, and finishing with a success status.
Common Pitfalls
- Ignoring the Context: If your
Dockerfileexpects files that aren't in the root, ensure thecontextparameter in your action is set to the correct directory. - Missing BuildKit: Trying to use advanced features without the
setup-buildx-actionwill often result in confusing error messages. Always include the setup step. - Over-building: Don't build the image multiple times in the same job. If you need to test the image, build it once and use the resulting tag for subsequent steps.
Frequently Asked Questions

Q: Do I need to push the image to a registry to verify it?
A: No. By setting push: false, the image is built and stored in the local storage of the runner. If the build command exits with status code 0, the image is valid.
Q: Will this slow down my pipeline?
A: Initial builds take time, but the docker/build-push-action handles caching. If your Dockerfile is optimized (e.g., placing COPY instructions after RUN npm install), subsequent builds will be very fast.
Q: Can I build multiple images in one pipeline? A: Yes, you can add multiple build steps or use a matrix strategy if you have a microservices architecture.
Recap

In this lesson, we moved beyond testing code to validating the packaging process. By adding a Docker build step to our CI pipeline, we've created a safeguard that prevents broken images from ever reaching the registry. We’ve utilized the official docker/build-push-action to ensure our builds are fast, cached, and reproducible.
Up next: We will learn how to handle sensitive configuration without hardcoding it, as we dive into Managing Secrets.
Work with me

CI/CD Pipeline & Docker Containerization
Ship with confidence: automated CI/CD pipelines and Docker setups so every push is tested and deployed — no more manual, error-prone releases.

AI Automation & Agentic Workflow Development
Automate the repetitive work eating your time — content pipelines, data workflows, and agentic AI tasks that run themselves.