Docker Build Fails in CI But Works Locally — Fix
Your Docker build works perfectly on your machine but fails in GitHub Actions, GitLab CI, or Jenkins. Here's every reason this happens and exactly how to fix it.
"Works on my machine" — the most frustrating phrase in DevOps. Your Docker build succeeds locally, the image runs fine, but CI fails every time.
Here's every reason this happens.
Quick Diagnosis
# In CI, add this before your docker build to see what's different
docker info
docker version
echo "Platform: $(uname -m)"
echo "Docker buildx: $(docker buildx version)"Case 1: Different Platform (arm64 vs amd64)
If you're on a Mac M1/M2/M3 (arm64) and CI runs on amd64 Linux, images built locally won't work in CI.
Symptom:
exec /usr/local/bin/node: exec format error
Fix: Build for the correct platform in CI:
# GitHub Actions
- name: Build Docker image
run: docker build --platform linux/amd64 -t myapp .Or use buildx for multi-platform:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
tags: myapp:latestCase 2: Build Context Too Large / .dockerignore Missing
Locally you have a warm Docker cache. In CI, everything is fresh and your build context might be huge.
Symptom: Build hangs at "Sending build context" for minutes.
Fix: Add .dockerignore:
# .dockerignore
node_modules
.git
.github
*.log
dist
.env
*.env
coverage
.DS_Store
Check context size:
# See what's being sent to Docker daemon
du -sh $(ls -A | grep -v .git) 2>/dev/null | sort -hr | head -20Case 3: Cache Not Available in CI
Your local build is fast because Docker caches layers. CI starts fresh — every build downloads everything.
Fix: Use GitHub Actions cache or registry cache:
# GitHub Actions with layer caching
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha # GitHub Actions cache
cache-to: type=gha,mode=maxOr use registry cache:
cache-from: type=registry,ref=myregistry/myapp:buildcache
cache-to: type=registry,ref=myregistry/myapp:buildcache,mode=maxCase 4: Missing Environment Variables / Build Args
You have .env locally but CI doesn't:
Symptom:
ERROR: "DB_URL" is required but not set
Fix: Pass build args in CI:
# GitHub Actions
- name: Build
run: |
docker build \
--build-arg NODE_ENV=production \
--build-arg API_URL=${{ secrets.API_URL }} \
-t myapp .In Dockerfile:
ARG NODE_ENV
ARG API_URL
ENV NODE_ENV=$NODE_ENVNever put secrets in image layers. Use --secret for sensitive values:
docker build --secret id=mysecret,env=MY_SECRET .# In Dockerfile
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret && npm installCase 5: Network Restrictions in CI
CI runners often have restricted network access. Package downloads that work locally fail in CI.
Symptom:
npm ERR! network timeout at: https://registry.npmjs.org/...
E: Failed to fetch http://archive.ubuntu.com/...
Fixes:
Use a private registry mirror:
# For npm
RUN npm install --registry https://your-nexus.internal/npm/
# For apt
RUN echo "deb http://your-mirror.internal/ubuntu focal main" > /etc/apt/sources.listOr cache dependencies in the Dockerfile correctly:
# Copy package.json FIRST (before source code)
# This layer is cached unless dependencies change
COPY package*.json ./
RUN npm ci --only=production
# THEN copy source
COPY . .Case 6: Different Docker Version
CI might use an older Docker that doesn't support features you use locally.
Symptom:
unknown flag: --mount
# or
OCI runtime create failed
Fix: Pin Docker version in CI:
# GitHub Actions — use specific buildx version
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
version: v0.12.0Or check what syntax features need a specific version:
# syntax=docker/dockerfile:1.5 ← requires BuildKit
# If CI doesn't have BuildKit enabled:
DOCKER_BUILDKIT=1 docker build .Enable BuildKit in CI:
env:
DOCKER_BUILDKIT: 1Case 7: File Permission Issues
Linux CI has different default umask than Mac:
Symptom:
permission denied: ./entrypoint.sh
Fix:
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh # Explicitly set permissionsOr set in COPY:
COPY --chmod=755 entrypoint.sh .Reproduce CI Locally
Test your CI environment locally using act:
# Install act (runs GitHub Actions locally)
brew install act # or download binary
# Run CI workflow locally
act push
# Run specific job
act -j buildThis runs the exact same Docker environment as GitHub Actions on your machine.
CI Docker Build Checklist
- Add
.dockerignore - Set
--platform linux/amd64if on Apple Silicon - Enable
DOCKER_BUILDKIT=1 - Add layer caching (
cache-from/cache-to) - Pass all required build args as CI secrets
- Test with
actbefore pushing
Learn Docker best practices with hands-on labs at KodeKloud — their Docker course covers multi-stage builds, BuildKit, and CI/CD integration.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Docker Build Taking Too Long — Cache and Speed Fixes (2026)
Docker builds taking 10+ minutes every time? Here's how to fix layer caching, use BuildKit properly, and cut build times by 80% with multi-stage builds and cache mounts.
GitHub Actions Docker Push: Permission Denied / Unauthorized Fix (2026)
Getting 'permission denied' or 'unauthorized: authentication required' when pushing Docker images in GitHub Actions? Here are all the causes and fixes.
AWS CodeBuild Build Failing or Timing Out — Fix Guide
CodeBuild exits with status 1, times out mid-build, or fails with cryptic phase errors. Here's how to diagnose DOWNLOAD_SOURCE, BUILD, and POST_BUILD failures with specific fixes.