Docker has been around for so long that most teams treat it as resolved tooling, yet I still find the same underutilized features. Here are ten practical capabilities that rarely make it into day-to-day workflows but deliver instant benefits of reliability and velocity.
1. Multi-stage builds keep product images small
Send only what you need. Use a heavy build phase and a clean runtime phase for the toolchain so you don’t leak compiler and cache into production layers.
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs22
COPY --from=build /app/dist /app
CMD ["server.js"]
pair it with --target When you need to run CI tasks inside intermediate steps without inflating the final artifact.
2. Turn BuildKit Cache Mount npm ci in milliseconds
Enable Buildkit (DOCKER_BUILDKIT=1) and add cache mounts, so there are expensive steps to reuse artifacts in all builds.
RUN --mount=type=cache,target=/root/.npm \
npm ci --prefer-offline
Treat cache mounts like shared volumes: never put secrets in them and don’t invalidate them periodically. --build-arg CACHE_BUST=$(date +%s) When dependencies change.
3. Secrets stay out of layers RUN --mount=type=secret
stop copying .env Convert files to images. BuildKit can inject secrets at build time that never persist into the final layer.
docker build \
--secret id=npmrc,src=$HOME/.npmrc \
-t web:secure .
RUN --mount=type=secret,id=npmrc target=/root/.npmrc \
npm publish
Now your source image remains clean, satisfying both the auditor and your future self.
4. Compose Profile Keep local, staging and product in one file
instead of jugaad docker-compose.dev.yml, *-prod.ymletc., define profiles and launch only what each environment requires.
services:
db:
image: postgres:16
profiles: [core]
mailhog:
image: mailhog/mailhog
profiles: [dev]
worker:
build: ./worker
profiles: [core, prod]
run docker compose --profile core --profile dev up during development and --profile core --profile prod up -d In staging. One file, zero drift.
5. buildx bake Lets you ship multi-arch binaries without CI spaghetti
When you need both AMD64 and Arm64 images (hello, Apple Silicon), docker buildx bake Reads a declarative file and handles the matrix in parallel.
// docker-bake.hcl
target "app" {
context = "."
dockerfile = "Dockerfile"
platforms = ["linux/amd64", "linux/arm64"]
tags = ["registry.example.com/app:latest"]
}
docker buildx bake app --push Now emits both variants and a manifest list, so Kubernetes automatically pulls the correct architecture.
6. Health checks and dependency awareness hinder fast-growing startups
Add HEALTHCHECK Directives and strings dependencies via Compose depends_on With conditions to avoid race conditions at launch.
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
services:
api:
depends_on:
db:
condition: service_healthy
Your Orchestrator now waits for Postgres to pass its checks before starting the API, preventing “works on my laptop” startup issues.
7. docker scout cves Provides immediate supply-chain response
Docker Scout plugs into hub or private registries and surfaces CVEs without leaving your terminal.
docker scout cves my-api:latest
Combine Scout with built-in SBOM export (docker buildx imagetools inspect --format '{{json .SBOM}}') to feed the actual dependency metadata to your security scanners.
8. Experiment --init, --cap-dropand tmpfs for production-grade containers
PID 1 is needed to retrieve the zombie, and most workloads require fewer Linux capabilities than Docker grants by default.
docker run --init \
--cap-drop=ALL --cap-add=NET_BIND_SERVICE \
--read-only --tmpfs /tmp:size=64m \
my-api:latest
These flags turn a “good enough” container into something you can actually defend during an audit.
9. Debug Product Locally with Similarity docker run --network container:
Need to find a service that is only connected to localhost inside its container? Launch a one-off toolbox container that shares the target network namespace.
TARGET=$(docker ps --filter name=redis -q)
docker run -it --network container:$TARGET nicolaka/netshoot redis-cli -h 127.0.0.1
No port-forward, no compose editing, just immediate shell access for diagnostics.
10. Stream Docker events to detect flutter containers
docker events --filter type=container Real time feed of start/stop cycles. put a pipe in it jq Or stack your observational capabilities to detect unhealthy workloads.
docker events --format '{{json .}}' | jq 'select(.status=="die")'
For long-running hosts, forward critical events to OneUptime (or your event manager of choice) so you don’t learn about container churn from customer tickets.
Docker is still evolving rapidly – even experienced operators miss out when they freeze their knowledge docker runPick one or two of these superpowers each sprint, bake them into your Dockerfile or compose template, and you’ll ship lean, secure containers without adding new tooling,
<a href