# Docker Multi-Stage Optimization {#docker-multi-stage-optimization}


Optimize Docker builds for smaller, faster images.


## Multi-Stage Build Pattern {#multi-stage-build-pattern}


```dockerfile
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile --production=false

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build:api

# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

# Copy only production artifacts
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# Non-root user
RUN addgroup -g 1001 gauzy && adduser -u 1001 -G gauzy -s /bin/sh -D gauzy
USER gauzy

EXPOSE 3000
CMD ["node", "dist/apps/api/main.js"]
```


## Size Comparison {#size-comparison}


| Stage               | Image Size |
| ------------------- | ---------- |
| Full node:20        | ~1.0 GB    |
| node:20-slim        | ~250 MB    |
| node:20-alpine      | ~150 MB    |
| Multi-stage (final) | ~180 MB    |


## Build Caching {#build-caching}


```dockerfile
# Copy dependency files first (better cache)
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Then copy source (changes more often)
COPY . .
RUN yarn build
```


## `.dockerignore` {#dockerignore}


```
node_modules
dist
.git
.env*
*.md
coverage
.nx
```


## Related Pages {#related-pages}


- [Container Security](https://sourcey-gauzy.pages.dev/devops/container-security/index.md) — security
- [Docker Deployment](https://sourcey-gauzy.pages.dev/deployment/docker/docker-setup/index.md) — Docker setup
- [GitHub Actions Caching](https://sourcey-gauzy.pages.dev/devops/github-actions-caching/index.md) — CI caching
