# Docker Patterns

> Dockerfile best practices, multi-stage builds, docker-compose for dev/prod. Use when setting up containerization for a NestJS backend or Next.js frontend, or configuring a local dev environment with docker-compose.

- **Type:** Skill
- **Install:** `agentstack add skill-sabahattink-antigravity-fullstack-hq-docker-patterns`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [sabahattink](https://agentstack.voostack.com/s/sabahattink)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [sabahattink](https://github.com/sabahattink)
- **Source:** https://github.com/sabahattink/antigravity-fullstack-hq/tree/main/skills/docker-patterns
- **Website:** https://github.com/sabahattink/antigravity-fullstack-hq

## Install

```sh
agentstack add skill-sabahattink-antigravity-fullstack-hq-docker-patterns
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Docker Patterns

## NestJS Multi-Stage Dockerfile

```dockerfile
# Dockerfile (backend)
# syntax=docker/dockerfile:1.5

FROM node:22-alpine AS base
WORKDIR /app
# Install only production deps in base
RUN corepack enable

# ─── deps stage ──────────────────────────────────────────────
FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

# ─── build stage ─────────────────────────────────────────────
FROM deps AS build
COPY . .
RUN pnpm run build

# ─── production stage ────────────────────────────────────────
FROM base AS production
ENV NODE_ENV=production

# Create non-root user
RUN addgroup --system --gid 1001 nodejs && \
    adduser  --system --uid 1001 nestjs

# Copy only what's needed to run
COPY --from=deps  --chown=nestjs:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=nestjs:nodejs /app/dist         ./dist
COPY --from=build --chown=nestjs:nodejs /app/package.json ./package.json

USER nestjs

EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:3000/health/liveness || exit 1

CMD ["node", "dist/main"]
```

## Next.js Multi-Stage Dockerfile

```dockerfile
# Dockerfile (frontend)
# syntax=docker/dockerfile:1.5
FROM node:22-alpine AS base
RUN corepack enable && apk add --no-cache libc6-compat
WORKDIR /app

# ─── deps ────────────────────────────────────────────────────
FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

# ─── build ───────────────────────────────────────────────────
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm run build

# ─── production ──────────────────────────────────────────────
FROM base AS runner
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
    adduser  --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000
ENV PORT=3000 HOSTNAME="0.0.0.0"

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:3000/api/health || exit 1

CMD ["node", "server.js"]
```

## .dockerignore

```
# .dockerignore
node_modules
.next
dist
.git
.gitignore
*.md
.env*
!.env.example
coverage
.nyc_output
*.log
.DS_Store
Thumbs.db
```

## next.config.ts for Standalone Build

```typescript
// next.config.ts
const nextConfig = {
  output: 'standalone',  // Required for Docker production builds
  experimental: {
    serverComponentsExternalPackages: ['@prisma/client'],
  },
}
export default nextConfig
```

## Docker Compose — Development

```yaml
# docker-compose.yml
version: '3.9'

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB:       ${POSTGRES_DB:-antigravity}
      POSTGRES_USER:     ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      retries: 5

  api:
    build:
      context: ./apps/api
      target: deps            # Use deps stage for hot reload
    restart: unless-stopped
    depends_on:
      postgres: { condition: service_healthy }
      redis:    { condition: service_healthy }
    environment:
      NODE_ENV:     development
      DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/${POSTGRES_DB:-antigravity}
      REDIS_URL:    redis://redis:6379
    ports:
      - "3001:3000"
      - "9229:9229"           # Debug port
    volumes:
      - ./apps/api/src:/app/src:ro
    command: pnpm run start:dev

  web:
    build:
      context: ./apps/web
      target: deps
    restart: unless-stopped
    depends_on: [api]
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:3001
    ports:
      - "3000:3000"
    volumes:
      - ./apps/web/src:/app/src:ro
      - ./apps/web/public:/app/public:ro
    command: pnpm run dev

volumes:
  postgres_data:
  redis_data:
```

## Docker Compose — Production Override

```yaml
# docker-compose.prod.yml
version: '3.9'

services:
  api:
    build:
      target: production       # Override to prod stage
    restart: always
    environment:
      NODE_ENV: production
    volumes: []                # No volume mounts in prod
    command: node dist/main    # Override dev command

  web:
    build:
      target: runner
    restart: always
    volumes: []
    command: node server.js

  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on: [web, api]
```

## Nginx Config

```nginx
# nginx/nginx.conf
events { worker_connections 1024; }

http {
    upstream api {
        server api:3000;
    }

    upstream web {
        server web:3000;
    }

    # Redirect HTTP to HTTPS
    server {
        listen 80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name example.com www.example.com;

        ssl_certificate     /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/privkey.pem;
        ssl_protocols       TLSv1.2 TLSv1.3;

        # Frontend
        location / {
            proxy_pass         http://web;
            proxy_http_version 1.1;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection 'upgrade';
            proxy_set_header   Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        # Backend API
        location /api/ {
            proxy_pass         http://api;
            proxy_http_version 1.1;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   Host $host;
            proxy_read_timeout 300s;
        }
    }
}
```

## Useful Commands

```bash
# Build and run
docker compose up -d --build

# View logs
docker compose logs -f api
docker compose logs --tail=100 web

# Exec into running container
docker compose exec api sh
docker compose exec postgres psql -U postgres antigravity

# Run database migration
docker compose exec api node dist/cli.js migrate:run

# Rebuild a single service
docker compose up -d --build api

# Production build
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build

# Clean up everything
docker compose down -v --remove-orphans
```

## Secrets Management

```yaml
# docker-compose.yml — use secrets for sensitive values
secrets:
  db_password:
    file: ./secrets/db_password.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt

services:
  api:
    secrets:
      - db_password
      - jwt_secret
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
      JWT_SECRET_FILE:        /run/secrets/jwt_secret
```

## Forbidden Patterns

- Never run containers as root in production — always create and use a non-root user
- Never put secrets in Dockerfile or docker-compose.yml — use secrets or env_file
- Never use `latest` tag for base images — pin to a specific digest or version
- Never copy `.env` files into the image — they get baked into layers permanently
- Never skip `.dockerignore` — `node_modules` in the image context wastes minutes
- Never run `npm install` in a production stage — install in a build stage, copy artifacts
- Never expose debug ports (9229) in production docker-compose
- Never commit `docker-compose.override.yml` with credentials to version control

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [sabahattink](https://github.com/sabahattink)
- **Source:** [sabahattink/antigravity-fullstack-hq](https://github.com/sabahattink/antigravity-fullstack-hq)
- **License:** MIT
- **Homepage:** https://github.com/sabahattink/antigravity-fullstack-hq

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-sabahattink-antigravity-fullstack-hq-docker-patterns
- Seller: https://agentstack.voostack.com/s/sabahattink
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
