Claude Code e Devcontainer: ambiente de desenvolvimento reproduzível
Monte um devcontainer Claude Code com Dockerfile, permissões, segredos, volumes e portas.
Claude Code rende mais quando o ambiente de desenvolvimento é previsível. Se uma pessoa usa Node.js 22, outra ainda está no Node.js 20, PostgreSQL está instalado de maneiras diferentes e Redis só existe em algumas máquinas, o agente passa tempo demais lidando com diferenças locais. Um devcontainer transforma essas decisões em configuração versionada.
Dev Container é um contêiner de desenvolvimento ao qual o editor se conecta. Terminal, servidor de linguagem, testes, ferramentas de banco de dados e Claude Code rodam dentro do mesmo ambiente Docker. Neste guia, vamos montar uma base para Next.js e TypeScript com PostgreSQL, Redis, Dockerfile, postCreateCommand, permissões, segredos, volumes e port-forward.
Em 2 de junho de 2026, a documentação oficial do Claude Code inclui uma página de Development containers, com orientações sobre a Feature oficial, persistência de credenciais, limites de rede e riscos de pular confirmações de permissão. Para o padrão do ambiente, consulte também a documentação de VS Code Dev Containers e a Dev Container Specification.
Por que devcontainer combina com Claude Code
Claude Code lê arquivos, altera código, executa comandos e interpreta falhas de teste. Isso é poderoso, mas depende de um ambiente claro. No shell do host, o agente pode enxergar pacotes globais antigos, credenciais pessoais, variáveis de outros projetos ou um banco local diferente do banco usado pelo time.
Com devcontainer, a superfície de trabalho vira código revisável. Versão do Node.js, pacotes do sistema, versão do CLI do Claude Code, extensões do VS Code, lifecycle commands, volumes e portas encaminhadas ficam no repositório. Quando Claude Code informa que executou npm test, o revisor sabe em qual contexto isso aconteceu.
flowchart LR
Host["Máquina host"] --> Editor["VS Code / Cursor"]
Editor --> Container["Dev Container"]
Container --> Claude["Claude Code CLI"]
Container --> Tools["Node.js / npm / psql / redis-cli"]
Container --> Services["PostgreSQL / Redis"]
Container --> Repo["Repositório montado"]
Claude --> Repo
Claude --> Tools
Os três casos de uso mais fortes são onboarding, desenvolvimento remoto e depuração assistida por IA. No onboarding, a pessoa nova reconstrói o contêiner e recebe o mesmo conjunto de ferramentas. Em Codespaces ou máquinas remotas, a mesma pasta .devcontainer funciona sem depender do sistema operacional local. Na depuração, lint, typecheck e testes deixam de ser “funcionou na minha máquina”.
Arquivos da configuração
A configuração separa aplicação, serviços e estado do Claude Code. Isso evita montar o diretório home inteiro do host por conveniência.
| Arquivo | Função | O que revisar |
|---|---|---|
.devcontainer/devcontainer.json | Entrada lida pelo editor | remoteUser, portas, mounts, lifecycle commands |
.devcontainer/Dockerfile | Instala ferramentas e Claude Code | versão do CLI, usuário não root, pacotes do sistema |
.devcontainer/docker-compose.yml | Sobe app, PostgreSQL e Redis | volumes, health checks, portas publicadas |
.devcontainer/post-create.sh | Setup após criação | lockfile, Prisma, tratamento de falhas |
.claude/settings.json | Regras de permissão | .env, segredos, git push e comandos Docker destrutivos |
devcontainer.json pronto para copiar
Crie .devcontainer/devcontainer.json. O arquivo precisa ser JSON válido, sem comentários.
{
"name": "claude-code-next-dev",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/app",
"remoteUser": "node",
"shutdownAction": "stopCompose",
"waitFor": "postCreateCommand",
"postCreateCommand": "bash .devcontainer/post-create.sh",
"postStartCommand": "git config --global --add safe.directory /workspaces/app || true",
"forwardPorts": [3000, 5432, 6379],
"portsAttributes": {
"3000": { "label": "Next.js", "onAutoForward": "notify" },
"5432": { "label": "PostgreSQL", "onAutoForward": "silent" },
"6379": { "label": "Redis", "onAutoForward": "silent" }
},
"mounts": [
"source=claude-code-config-${devcontainerId},target=/home/node/.claude,type=volume"
],
"containerEnv": {
"NODE_ENV": "development",
"DISABLE_AUTOUPDATER": "1",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
},
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"typescript.tsdk": "node_modules/typescript/lib",
"terminal.integrated.defaultProfile.linux": "bash"
}
}
}
}
remoteUser deve ser um usuário não root. O contêiner reduz o risco, mas o workspace continua montado a partir do host. Se Claude Code apagar arquivos em /workspaces/app, o repositório local também muda. O volume em /home/node/.claude preserva a configuração do Claude Code entre rebuilds sem expor todo o home do host.
Docker Compose, Dockerfile e postCreateCommand
O arquivo .devcontainer/docker-compose.yml sobe app, PostgreSQL e Redis. Comece com forwardPorts; publicar portas de banco com Compose só faz sentido quando uma ferramenta externa realmente precisa.
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
command: sleep infinity
volumes:
- ..:/workspaces/app:cached
- node_modules:/workspaces/app/node_modules
- claude_code_config:/home/node/.claude
environment:
DATABASE_URL: postgresql://app:app_password@db:5432/app
REDIS_URL: redis://redis:6379
NEXT_TELEMETRY_DISABLED: "1"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app_password
POSTGRES_DB: app
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 5s
retries: 20
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 20
volumes:
node_modules:
claude_code_config:
postgres_data:
redis_data:
No Dockerfile, fixe a versão do Claude Code. Em 2 de junho de 2026, npm view @anthropic-ai/claude-code version retornou 2.1.160.
FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm
ARG CLAUDE_CODE_VERSION=2.1.160
ENV DISABLE_AUTOUPDATER=1
ENV NEXT_TELEMETRY_DISABLED=1
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
jq \
postgresql-client \
redis-tools \
ripgrep \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" \
&& npm cache clean --force
USER node
WORKDIR /workspaces/app
RUN mkdir -p /home/node/.claude
O setup inicial fica em .devcontainer/post-create.sh.
#!/usr/bin/env bash
set -euo pipefail
cd /workspaces/app
corepack enable
if [ -f pnpm-lock.yaml ]; then
pnpm install --frozen-lockfile
elif [ -f yarn.lock ]; then
yarn install --immutable
elif [ -f package-lock.json ]; then
npm ci
elif [ -f package.json ]; then
npm install
fi
if [ -f prisma/schema.prisma ]; then
npx prisma generate
fi
node --version
npm --version
claude --version || true
Esse script respeita o lockfile do projeto e falha cedo quando algo está quebrado. Não coloque npm run dev em postCreateCommand; servidor permanente deve rodar em terminal, task ou serviço próprio.
Permissões, segredos, volumes e port-forward
Não monte ~/.ssh, ~/.aws, ~/.config/gcloud ou .env de produção por padrão. O segredo mais seguro é o que nunca entra no contêiner. Variáveis de desenvolvimento podem apontar para serviços internos do Compose; segredos reais devem usar secrets gerenciados ou tokens temporários.
As regras do Claude Code podem ficar em .claude/settings.json.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"Bash(npm run typecheck)",
"Bash(claude --version)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(printenv *)",
"Bash(git push *)",
"Bash(docker system prune *)"
]
}
}
Volumes ajudam, mas também guardam estado ruim. node_modules deve ficar em volume do contêiner para evitar mistura de módulos nativos de Windows ou macOS com Linux. O volume do PostgreSQL precisa de regra de limpeza, porque migrações de teste podem deixar o banco em um estado antigo.
Erros comuns e verificação
Erros comuns: rodar Claude Code como root, não fixar o CLI, montar segredos de produção, iniciar processos longos em postCreateCommand e publicar portas de banco sem necessidade. Cada item parece pequeno, mas juntos quebram a confiança no resultado do agente.
Depois do rebuild, verifique node --version, npm --version, claude --version, pelo menos um lint ou test, e http://localhost:3000. Confirme que .env, .env.local e secrets/** não estão acessíveis ao Claude Code e que PostgreSQL e Redis não foram expostos além do necessário.
Para aprofundar Compose, leia o guia Docker Compose com Claude Code. Para ligar isso ao fluxo de deploy, veja o guia de CI/CD com Claude Code. Se o time quer padronizar devcontainer, CLAUDE.md, permissões e revisão de qualidade, comece por training / consultation.
Resultado prático
Em um repositório pequeno de Next.js, o maior ganho veio de separar postCreateCommand em script, colocar node_modules em volume do contêiner e preservar /home/node/.claude por projeto. A cada rebuild, versão do Claude Code, instalação de dependências, geração do Prisma e porta 3000 eram verificáveis do mesmo jeito. O ponto de atenção foi o volume do banco após várias migrações de teste. Reprodutibilidade depende de versão fixa, fronteira de segredos, regra de volume e disciplina de portas ao mesmo tempo.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Como pedir ao Claude Code para mexer em um único arquivo
Do desastre em que um 'deixa melhor' alterou 40 linhas nasceu um template de prompt que limita o escopo, valida e permite reverter.
Recuperar de negações de permissão no Claude Code sem enfraquecer guardrails
Transforme um comando negado em plano seguro com motivo, alternativa, provas e critérios de nova tentativa.
Claude Code Harness Smoke Test: prova de 15 minutos antes de confiar em um agente
Um smoke test para escopo, áreas bloqueadas, comandos de prova, URL pública e CTAs de receita no Claude Code.