A minimal runnable Node image skeleton
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Use the JSON array form for CMD so it skips the shell.
Copy-ready snippets from a minimal image to multi-stage builds, layer caching, non-root users and slim images.
A minimal runnable Node image skeleton
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Use the JSON array form for CMD so it skips the shell.
Pin a minor base image tag so builds stay reproducible
FROM node:20-alpine3.20Add source metadata labels to trace the image
LABEL org.opencontainers.image.source="https://github.com/acme/my-app"Document the listening port; it does not publish anything
EXPOSE 3000Multi-stage Go build that ships only the binary
FROM golang:1.22-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/server
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]Build the frontend, then serve it with Nginx
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.25-alpine
COPY --from=build /app/dist /usr/share/nginx/htmlStatic binaries can run from scratch for the smallest size
FROM scratch
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]scratch has no shell or CA certs; copy them if needed.
Copy manifests first so code edits reuse the dependency layer
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .Cache the package manager directory with BuildKit
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=devRequires BuildKit, enabled by default since Docker 23.
Use .dockerignore to shrink context and keep secrets out
node_modules
dist
.git
.env
DockerfileSet ownership during copy to skip an extra chown layer
COPY --chown=node:node . .Create and switch to a non-root user for the process
RUN addgroup -S app && adduser -S app -G app
USER appEnsure the working directory is writable before switching.
Declare a health check for orchestrators to poll
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://127.0.0.1:3000/health || exit 1Slim images may lack curl; use wget or a bundled script.
Fix the entrypoint while letting CMD be overridden
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["--config", "/etc/app/config.yaml"]In exec form they concatenate; shell form ignores CMD.
Declare the stop signal for graceful shutdown
STOPSIGNAL SIGTERMPass build-time variables; never use it for secrets
docker build --build-arg NODE_ENV=production -t my-app:1.0 .ARG values stay in image history and show up in docker history.
Build only up to one stage to debug intermediate output
docker build --target build -t my-app:builder .Build the image for a given architecture
docker build --platform linux/amd64 -t my-app:1.0 .Cross-arch builds need buildx and can be slow locally.
Rebuild ignoring all cache to debug stale layers
docker build --no-cache -t my-app:1.0 .Point to another Dockerfile; the last argument is the context
docker build -f docker/Dockerfile.prod -t my-app:1.0 .Install and clean apt lists within a single layer
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*Install production dependencies and drop the npm cache
RUN npm ci --omit=dev && npm cache clean --forcePrefer alpine or slim images as the base
FROM node:20-slimUse --no-cache on Alpine to skip manual index cleanup
RUN apk add --no-cache curlThis website uses cookies to ensure you get the best experience on our website. Privacy Policy.