How I Cut Docker Build Times from 20 Minutes to 4 Minutes

How I Cut Docker Build Times from 20 Minutes to 4 Minutes

@brankopetric00

How I Cut Docker Build Times from 20 Minutes to 4 Minutes

20 minutes. That's how long every build took for OpenTweet.

For context, OpenTweet is a free X (Twitter) scheduler that helps you schedule posts, manage threads, and track analytics. It's built with Next.js and deployed in Docker containers. Pretty standard stack, nothing fancy.

But our builds? Painfully slow.

Change one line of code? 20 minutes. Fix a typo? 20 minutes. Push 5 times a day and you've just burned 2 hours staring at GitHub Actions spin.

When you're trying to ship features fast and respond to user feedback, waiting 20 minutes per deploy kills momentum.

So I spent an afternoon fixing it. Here's what worked.


The Problem

Our GitHub Actions workflow was building for two platforms (amd64 and arm64), downloading npm packages fresh every time, and using Docker Hub's registry cache.

Spoiler: it was all unnecessary.


Fix #1: GitHub Actions Cache

Docker Hub's registry cache is slow. GitHub Actions cache is fast because it's in the same datacenter.

- name: Cache Docker layers
  uses: actions/cache@v4
  with:
    path: /tmp/.buildx-cache
    key: ${{ runner.os }}-buildx-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-buildx-

Point BuildKit at it:

cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max

First build? Still slow. Second build? 3 minutes. 85% faster.


Fix #2: Drop ARM Builds

We were building for arm64. Why? Nobody knows. We deploy to x86 servers.

platforms: linux/amd64

Saved 5-7 minutes instantly. If you don't deploy to ARM, don't build for ARM.


Fix #3: Cache npm Packages

BuildKit can cache npm packages between builds:

RUN --mount=type=cache,target=/root/.npm \
    npm ci --prefer-offline --no-audit

Saves 1-2 minutes. Small win, but it adds up.


Fix #4: Clean Up .dockerignore

Stop copying stuff Docker doesn't need:

node_modules/
.git/
.github/
*.md
.env*

Smaller context = faster builds.


Fix #5: Multistage Docker Builds

This was a game changer I should've done from day one.

Before, we were using a single-stage Dockerfile. This meant the final image included all the build dependencies, source files, and npm cache - stuff you don't need in production.

Here's what I switched to:

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --prefer-offline --no-audit
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]

The first stage builds everything. The second stage only copies what's needed to run the app.

Result? Image size dropped from 1.2GB to 400MB. Faster pulls, faster deploys, and OpenTweet users get updates deployed quicker.


Fix #6: Disable Next.js Telemetry

ENV NEXT_TELEMETRY_DISABLED=1

Next.js phones home during builds. We don't need that in CI. Saves ~30 seconds.


The Results

  • First build (cold cache): 20 min → 8-10 min
  • Warm cache: 20 min → 2-3 min
  • Typical build: 20 min → 4-6 min

The Takeaway

Fast builds change how you work. When builds take 20 minutes, you avoid pushing. You batch changes. You lose flow.

When builds take 4 minutes, you push confidently. You iterate faster. You ship faster.

For OpenTweet, this meant I could respond to user requests same-day instead of batching changes. Someone reports a bug? Fixed and deployed within the hour. New scheduling feature requested? Ship it that afternoon.

The whole setup took 2 hours. Worth every minute.

If you're waiting on Docker builds, switch to GitHub Actions cache, use multistage builds, drop the extra platform, and clean up your build context. Your future self will thank you.

Start Scheduling Your X Posts Today

Join hundreds of creators using OpenTweet to stay consistent, save time, and grow their audience.

7-day free trial
Only $5.99/mo
Cancel anytime