Use Cases (Updated: 6/3/2026)

Claude Code and Docker: Compose, Volumes, Networks, and CI Builds

Build safer Dockerfiles, Compose stacks, and CI image checks with Claude Code.

Claude Code and Docker: Compose, Volumes, Networks, and CI Builds

Decide What Claude Code Should Own

If you ask Claude Code to “Dockerize this app” without constraints, it may produce a Dockerfile that runs once but is hard to review. Docker is a way to package an application runtime: an image is the template, a container is the running instance, a volume keeps data outside the container, and a network lets services talk to each other by name.

For production-minded work, do not treat the Dockerfile as the whole task. Review the Dockerfile, docker-compose.yml, .dockerignore, environment variables, health checks, and CI build together. Keep the primary references open: Dockerfile reference, Compose file reference, Docker build best practices, Docker Build with GitHub Actions, and the Claude Code overview.

For adjacent work, pair this article with Claude Code CI/CD setup, Claude Code approval and sandbox guide, and Claude Code security best practices.

Four Practical Use Cases

Docker integration is useful when it removes ambiguity from daily work. Name the job before asking Claude Code to edit files.

Use caseWhat Docker standardizesWhat to ask Claude Code
New developer onboardingNode.js, PostgreSQL, Redis, ports, startup commandsMake docker compose up boot the stack
Production-like debuggingEnv vars, service names, health checks, startup orderList local vs production differences
Pull request verificationDockerfile, lockfile, build cache, CI logsAdd a workflow that builds the image
Training and handoffCommands, failure modes, recovery stepsWrite CLAUDE.md and README rules

This matters for monetized software. If checkout, lead forms, admin screens, or product pages only work on one laptop, revenue depends on an unreviewed local state. Solo builders can start with ClaudeCodeLab products. Teams that want repository-specific rules, permissions, CI checks, and rollout support can use Claude Code training and consultation.

Prompt Claude Code With Guardrails

Give Claude Code the target, requested files, forbidden behavior, and verification commands in one prompt. This prevents a plausible but unsafe Docker setup.

Dockerize this Node.js + TypeScript API.

Context:
- pnpm is the package manager.
- The app listens on port 3000.
- GET /health returns 200.
- Local development needs PostgreSQL 16 and Redis 7.

Create:
- Production multi-stage Dockerfile
- docker-compose.yml for local development
- .dockerignore
- Docker-related package.json scripts
- GitHub Actions workflow that only verifies docker build

Constraints:
- Do not run the production container as root.
- Do not COPY .env files or secrets into the image.
- Explain the volume and network choices for the README.
- Include verification commands and how to inspect failures.

A multi-stage build separates the build environment from the runtime environment. TypeScript compilation tools stay out of the final image, while the runtime stage receives only production dependencies and compiled output.

Copy-Paste Dockerfile

This example assumes a Node.js API that builds src/index.ts into dist/index.js. The dev stage supports Compose-based local development. The runner stage is the production image.

# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
WORKDIR /app
RUN corepack enable

FROM base AS dev
ENV NODE_ENV=development
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
CMD ["pnpm", "dev"]

FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

FROM deps AS build
COPY tsconfig.json ./
COPY src ./src
RUN pnpm build

FROM base AS prod-deps
ENV NODE_ENV=production
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod && pnpm store prune

FROM base AS runner
ENV NODE_ENV=production
RUN groupadd --system --gid 1001 nodejs \
  && useradd --system --uid 1001 --gid nodejs appuser
COPY --from=prod-deps --chown=appuser:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=appuser:nodejs /app/dist ./dist
COPY --chown=appuser:nodejs package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD node -e "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["node", "dist/index.js"]

Ask Claude Code to review the file for three things: whether secrets can enter the image, whether the COPY order preserves cache efficiency, and whether development dependencies are excluded from the runtime image.

Compose: Volumes and Networks Without Mystery

Compose starts multiple containers together. In this stack, the API, PostgreSQL, and Redis share a network, so the API connects to postgres and redis by service name. Volumes keep state outside the disposable container. pgdata preserves database files, and api_node_modules prevents host node_modules from overriding container dependencies.

services:
  api:
    build:
      context: .
      target: dev
    command: pnpm dev
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      DATABASE_URL: postgres://app:app@postgres:5432/app
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - .:/app
      - api_node_modules:/app/node_modules
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 10s
      timeout: 3s
      retries: 5

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 10

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  pgdata:
  api_node_modules:

depends_on controls startup order. It does not automatically prove that a database is ready unless you combine it with health checks. That is why the example waits for service_healthy.

Keep Secrets Out of the Build Context

Start with .dockerignore. It reduces build context size and prevents accidental secret copies.

.git
node_modules
dist
coverage
.env
.env.*
!.env.example
npm-debug.log*
pnpm-debug.log*
Dockerfile*
docker-compose*.yml

Then add scripts that the team can run without memorizing command sequences.

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc -p tsconfig.json",
    "start": "node dist/index.js",
    "docker:dev": "docker compose up --build",
    "docker:check": "bash scripts/docker-check.sh"
  },
  "dependencies": {
    "@fastify/redis": "latest",
    "fastify": "latest",
    "pg": "latest"
  },
  "devDependencies": {
    "tsx": "latest",
    "typescript": "latest"
  }
}

Add a Repeatable Verification Script

Manual verification is easy to skip. Put the check in scripts/docker-check.sh and ask Claude Code to keep it updated when services change.

#!/usr/bin/env bash
set -euo pipefail

docker compose build api
docker compose up -d postgres redis api

cleanup() {
  docker compose down
}
trap cleanup EXIT

for attempt in {1..30}; do
  if curl -fsS http://127.0.0.1:3000/health >/dev/null; then
    echo "healthcheck ok"
    exit 0
  fi
  echo "waiting for api... ${attempt}/30"
  sleep 2
done

docker compose logs api
exit 1

This script builds the API image, starts the stack, waits for the health endpoint, and prints logs when the service never becomes healthy.

CI: Build First, Push Later

The first pull request should verify the image build without publishing anything to a registry. Add push, signing, vulnerability scanning, and SBOM generation after the base image is stable.

name: docker-build

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/build-push-action@v7
        with:
          context: .
          target: runner
          push: false
          tags: claude-code-docker-sample:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Ask Claude Code to explain whether this workflow pushes anything, whether the permissions are larger than needed, and how the job behaves when the cache is empty.

Common Failure Modes

The most expensive mistake is copying .env into the image. Once a secret enters a registry, cleanup is slow. Always check .dockerignore, CI secrets, and build logs together.

Another common failure is mounting host node_modules into a Linux container. Native packages can differ across macOS, Windows, and Linux. Keeping api_node_modules as a named volume avoids that cross-platform mismatch.

The third failure is a startup race: the API starts before the database is ready. Combine database health checks, service_healthy, and application-level retries.

The fourth failure is running the production container as root. It often works in demos, but it expands the blast radius of an application vulnerability. Ask Claude Code to point to the exact Dockerfile lines that prove the runtime user is non-root.

Safe Development Workflow

The safest order is: inspect the repository, list runtime dependencies, write .dockerignore, create local Compose, create the production Dockerfile, add the verification script, then add CI. After each step, read the diff and ask Claude Code for four short receipts: changed files, reason, verification command, and remaining risk.

This works well with session handoff templates because another developer can continue without guessing. Docker integration should become a repeatable team habit, not a one-time generated file.

What Happened in Practice

In practice, smaller Claude Code tasks produced better Docker work. Starting with .dockerignore, then Compose, then health checks, then CI reduced review churn. The named node_modules volume and database health gates prevented the two beginner issues that show up most often: “it works only on my machine” and “the API started but cannot connect to Postgres.”

#Claude Code #Docker #containers #DevOps #infrastructure
Free

Free PDF: Claude Code Cheatsheet

Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.

We handle your data with care and never send spam.

Level up your Claude Code workflow

Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.