Dockerizing Fastify

Small Image, Multi-Stage Build

Dockerizing Fastify

A multi-stage Dockerfile builds with dev dependencies and ships only production deps for a small, fast image.

4 min read Level 2/5 #fastify#docker#deployment
What you'll learn
  • Write a multi-stage Dockerfile
  • Use node-slim or alpine base images
  • Add HEALTHCHECK for orchestrators

A Fastify image should be small, reproducible, and run as a non-root user. The shape that works almost everywhere is a multi-stage Dockerfile: build with dev deps, ship with prod deps.

Multi-Stage Dockerfile

FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
HEALTHCHECK --interval=10s --timeout=3s \
  CMD wget -qO- http://localhost:3000/healthz || exit 1
USER node
CMD ["node", "dist/index.js"]

The build stage compiles TypeScript with dev dependencies. The runtime stage installs only production deps and copies dist/, leaving a slim image (~150 MB on alpine).

.dockerignore

Without this, you’ll bake node_modules, .git, and secrets into the image.

# .dockerignore
node_modules
.git
.env
.env.*
dist
coverage

Build and Run

docker build -t my-api .
docker run --rm -p 3000:3000 --env-file .env my-api

For local dev, use a separate Dockerfile.dev with tsx --watch and a bind mount — keep production images lean.

Deployment Targets →