Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Docker Compose para Node.js

Atualizado em: 18 de setembro de 2026

Terminal Linux usado em desenvolvimento e administração de aplicações Node.js

O Docker Compose para Node.js permite definir API, PostgreSQL, Redis, workers, proxies e ferramentas de observabilidade em um único arquivo YAML. Com um comando, a equipe cria redes, volumes e containers com configuração reproduzível para desenvolvimento, testes e ambientes controlados.

Compose simplifica a execução local, mas não corrige automaticamente uma imagem ruim ou uma aplicação que ignora sinais. É necessário definir healthchecks, volumes adequados, variáveis, secrets, limites e dependências. Também é importante separar conveniência de desenvolvimento das práticas usadas em produção.

Neste guia, você aprenderá a criar um compose.yaml para Node.js, configurar PostgreSQL e Redis, usar healthchecks, networks, volumes, profiles, watch, múltiplos arquivos, secrets, shutdown e CI.

O que é Docker Compose?

A documentação oficial do Docker Compose define a ferramenta como uma forma de declarar e executar aplicações com múltiplos containers. Serviços, redes, volumes e configurações ficam em um arquivo YAML.

A referência completa é a Compose Specification.

Estrutura do projeto

project/
├── compose.yaml
├── compose.override.yaml
├── Dockerfile
├── package.json
├── package-lock.json
├── src/
└── scripts/
    └── wait-for-migrations.js

O arquivo principal contém a base compartilhada. Overrides adicionam configurações de desenvolvimento ou produção.

Primeiro compose.yaml

services:
  api:
    build:
      context: .
      target: development
    command: npm run dev
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      PORT: 3000
      DATABASE_URL: postgresql://app:app@postgres:5432/app
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  postgres:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 10

  redis:
    image: redis:8
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  postgres_data:
  redis_data:

Iniciando os serviços

docker compose up

Em background:

docker compose up -d

Construindo novamente:

docker compose up --build

Nome dos serviços como DNS

Dentro da rede do projeto, a API acessa:

postgres:5432
redis:6379

localhost dentro do container aponta para o próprio container, não para outro serviço.

Portas

ports:
  - "3000:3000"

O primeiro número é a porta no host; o segundo, no container. PostgreSQL não precisa ser publicado quando somente a aplicação o utiliza. Remover portas desnecessárias reduz exposição.

Expose

expose:
  - "3000"

expose documenta a porta entre containers, mas não publica no host. A comunicação na rede Compose já funciona sem ele quando o serviço escuta corretamente.

Dockerfile multi-stage

FROM node:22-bookworm-slim AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM dependencies AS development
COPY . .
CMD ["npm", "run", "dev"]

FROM dependencies AS build
COPY . .
RUN npm run build
RUN npm prune --omit=dev

FROM node:22-bookworm-slim AS production
ENV NODE_ENV=production
WORKDIR /app
USER node
COPY --from=build --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
COPY --from=build --chown=node:node /app/package.json ./package.json
CMD ["node", "--enable-source-maps", "dist/server.js"]

Consulte Docker Multi-stage para Node.js.

.dockerignore

node_modules
dist
coverage
.git
.env
*.log
compose*.yaml

Não envie secrets, dependências locais e histórico Git ao build context.

Bind mount em desenvolvimento

services:
  api:
    volumes:
      - .:/app
      - node_modules:/app/node_modules

volumes:
  node_modules:

O volume separado evita que o node_modules do host substitua dependências Linux do container.

Compose Watch

Versões atuais oferecem watch:

services:
  api:
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: package-lock.json

Execute:

docker compose watch

Sync reduz problemas de performance de bind mounts em alguns sistemas. Confirme as ações suportadas pela versão instalada.

Variáveis de ambiente

environment:
  NODE_ENV: development
  PORT: 3000

Ou:

env_file:
  - .env.compose

Não versiona arquivos com secrets. Entenda a precedência entre shell, .env, env_file e environment.

Veja Variáveis de Ambiente no Node.js.

Interpolação

ports:
  - "${APP_PORT:-3000}:3000"

Para exigir uma variável:

image: "registry.example.com/app:${IMAGE_TAG:?IMAGE_TAG obrigatório}"

Use:

docker compose config

O comando mostra a configuração resolvida. Cuidado: ele pode exibir valores sensíveis.

Secrets

services:
  api:
    secrets:
      - database_password

secrets:
  database_password:
    file: ./secrets/database_password.txt

Dentro do container, o secret fica normalmente em:

/run/secrets/database_password

Compose local monta arquivos; isso não oferece automaticamente as mesmas garantias de Docker Swarm ou um secret manager. Proteja o arquivo e não o versione.

Consulte Gestão de Segredos no Node.js.

Healthcheck da API

healthcheck:
  test:
    - CMD
    - node
    - -e
    - |
      fetch('http://127.0.0.1:3000/health/ready')
        .then(r => process.exit(r.ok ? 0 : 1))
        .catch(() => process.exit(1))
  interval: 10s
  timeout: 3s
  retries: 5
  start_period: 20s

Veja Docker Healthcheck no Node.js.

depends_on não é readiness por padrão

A forma curta controla ordem de início, não espera que o serviço esteja pronto:

depends_on:
  - postgres

Use condition com healthcheck:

depends_on:
  postgres:
    condition: service_healthy

A aplicação ainda precisa tolerar desconexão e reconectar. O banco pode cair depois do startup.

Migrations

Crie um serviço one-off:

services:
  migrate:
    build:
      context: .
      target: build
    command: npm run migrate
    environment:
      DATABASE_URL: postgresql://app:app@postgres:5432/app
    depends_on:
      postgres:
        condition: service_healthy
    profiles: ["tools"]

Execute:

docker compose --profile tools run --rm migrate

Consulte Migrações de Banco no Node.js.

Profiles

services:
  mailpit:
    image: axllent/mailpit
    ports:
      - "8025:8025"
    profiles: ["dev-tools"]
docker compose --profile dev-tools up

Profiles mantêm ferramentas opcionais fora do startup padrão.

Workers

services:
  worker:
    build:
      context: .
      target: development
    command: npm run worker:dev
    environment:
      DATABASE_URL: postgresql://app:app@postgres:5432/app
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

API e worker usam a mesma imagem, mas comandos diferentes.

Escalando localmente

docker compose up --scale worker=3

Não publique uma porta fixa do host para cada réplica. O broker ou banco deve distribuir o trabalho com idempotência.

Networks

services:
  api:
    networks: [frontend, backend]
  postgres:
    networks: [backend]
  nginx:
    networks: [frontend]

networks:
  frontend:
  backend:
    internal: true

A rede interna evita acesso direto ao banco por serviços externos à rede.

Volumes nomeados

volumes:
  postgres_data:

Liste:

docker volume ls

Remova containers sem apagar dados:

docker compose down

Remova também volumes:

docker compose down -v

Use -v somente quando realmente deseja perder o banco local.

Backup local

docker compose exec -T postgres \
  pg_dump -U app -d app \
  > backup.sql

Restore:

docker compose exec -T postgres \
  psql -U app -d app \
  < backup.sql

Logs

docker compose logs -f api worker

A aplicação deve escrever logs estruturados em stdout e stderr. Não grave arquivos sem rotação dentro do container.

Comandos úteis

docker compose ps
docker compose top
docker compose images
docker compose exec api sh
docker compose run --rm api npm test
docker compose restart api
docker compose stop
docker compose down

Múltiplos arquivos

Base:

docker compose -f compose.yaml -f compose.dev.yaml up

Produção:

docker compose -f compose.yaml -f compose.prod.yaml config

Revise as regras de merge. Arrays e mappings podem ser combinados de formas diferentes.

Override automático

compose.override.yaml é carregado automaticamente com o arquivo padrão. Use para desenvolvimento local e mantenha a base segura.

Configuração de produção

services:
  api:
    build:
      target: production
    command: node --enable-source-maps dist/server.js
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true

Compose pode ser usado em host único, mas não oferece todas as capacidades de um orquestrador. Avalie rolling updates, secrets, autoscaling, scheduling e alta disponibilidade.

Usuário não-root

Defina USER node no Dockerfile. Se montar volumes, confirme permissões. Não execute como root apenas para contornar erros de escrita.

Filesystem read-only

read_only: true
tmpfs:
  - /tmp

Adicione volumes somente nos caminhos que realmente precisam ser graváveis.

Capabilities

cap_drop:
  - ALL

Adicione uma capability somente se a aplicação necessita. APIs Node.js comuns não precisam de privilégios Linux extras.

Docker socket

Evite montar:

/var/run/docker.sock:/var/run/docker.sock

Acesso ao socket equivale a controle elevado do host em muitos cenários.

Limites de recursos

services:
  api:
    mem_limit: 512m
    cpus: 1.0

A sintaxe e suporte variam conforme o modo. Teste e monitore OOM. Ajuste o heap do Node.js com margem para Buffers e memória nativa.

Graceful shutdown

Compose envia SIGTERM antes de SIGKILL. Configure:

stop_grace_period: 30s

A aplicação deve parar de aceitar tráfego, concluir trabalho, fechar conexões e sair. Veja Graceful Shutdown no Node.js.

Init

init: true

Um pequeno processo init encaminha sinais e coleta processos filhos. É útil quando a aplicação inicia child processes.

Testes de integração

docker compose -f compose.test.yaml up \
  --build \
  --abort-on-container-exit \
  --exit-code-from tests

Garanta cleanup:

docker compose -f compose.test.yaml down -v --remove-orphans

Compose no CI

- run: docker compose -f compose.test.yaml config
- run: docker compose -f compose.test.yaml build
- run: docker compose -f compose.test.yaml up --abort-on-container-exit --exit-code-from tests
- if: always()
  run: docker compose -f compose.test.yaml down -v --remove-orphans

Consulte CI para Node.js com GitHub Actions.

Fixe versões e digests

Evite depender apenas de:

image: postgres:latest

Prefira uma versão suportada e, em ambientes rigorosos, digest imutável. Atualize em pull requests testados.

Build secrets

Não passe tokens com ARG ou ENV durante build, pois podem aparecer em camadas. Use BuildKit secrets no Dockerfile e configuração de build correspondente.

Ambientes efêmeros

Defina project name diferente:

docker compose -p pr-123 up -d

Isso isola nomes de containers, networks e volumes. Remova tudo ao final.

Orphans

Quando um serviço é removido do YAML:

docker compose up --remove-orphans

Revise antes em ambientes com dados persistentes.

Configuração final validada

docker compose config --quiet

Inclua no CI para detectar YAML inválido e variáveis ausentes.

Erros comuns

  • localhost entre serviços: conexão aponta para o container errado.
  • depends_on sem healthcheck: API inicia antes do banco.
  • Portas desnecessárias: banco fica exposto.
  • .env versionado: secrets vazam.
  • Bind mount em produção: artefato não é imutável.
  • latest: atualização inesperada.
  • down -v sem cuidado: dados são apagados.
  • Aplicação sem SIGTERM: requisições são interrompidas.

Conclusão

O Docker Compose para Node.js reúne aplicação, banco, cache e workers em uma configuração reproduzível. Services, networks, volumes, healthchecks e profiles tornam desenvolvimento e testes mais consistentes.

Use imagens multi-stage, dependências saudáveis, secrets protegidos, portas mínimas e shutdown gracioso. Separe overrides de desenvolvimento da configuração de produção e valide o YAML no CI. Assim, Compose simplifica o ambiente sem esconder requisitos de segurança, persistência e disponibilidade.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita