Claude Code et Devcontainer : environnement de développement reproductible
Créez un devcontainer Claude Code reproductible avec Dockerfile, permissions, secrets, volumes et port-forward.
Claude Code devient beaucoup plus fiable quand l’environnement de développement est stable. Si une personne utilise Node.js 22, une autre Node.js 20, que PostgreSQL est installé différemment selon les machines et que Redis n’existe que chez certains développeurs, l’agent passe son temps à contourner des écarts d’environnement au lieu de résoudre le problème réel.
Un Dev Container transforme cette configuration en fichiers versionnés dans le dépôt. L’éditeur se connecte à un conteneur Docker, puis la terminale, le serveur de langage, les tests, les outils de base de données et Claude Code tournent dans le même contexte. Dans cet article, nous construisons un devcontainer pratique pour Next.js et TypeScript, avec PostgreSQL, Redis, Dockerfile, postCreateCommand, permissions, secrets, volumes et port-forward.
Au 2 juin 2026, la documentation officielle de Claude Code contient une page Development containers qui couvre la Feature officielle, la persistance des identifiants, les limites réseau et le risque de contourner les permissions. Pour la partie Dev Container, gardez aussi la documentation VS Code Dev Containers et la Dev Container Specification sous la main.
Pourquoi un devcontainer aide Claude Code
Claude Code ne se limite pas à proposer du texte. Il lit des fichiers, modifie du code, lance des commandes, interprète des échecs de tests et peut enchaîner plusieurs corrections. Cela exige un environnement explicite. Si l’agent tourne dans le shell du poste hôte, il peut voir d’anciens paquets globaux, des variables d’autres projets, des identifiants cloud personnels ou une base de données différente de celle du reste de l’équipe.
Avec un devcontainer, la surface de travail devient révisable. La version de Node.js, les paquets système, la version du CLI Claude Code, les extensions VS Code, les volumes, les ports et les commandes de cycle de vie sont dans le dépôt. Quand Claude Code indique qu’il a exécuté npm test, on sait dans quel contexte cette commande a tourné.
flowchart LR
Host["Machine hôte"] --> 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["Dépôt monté"]
Claude --> Repo
Claude --> Tools
Trois usages reviennent souvent. L’onboarding devient plus simple, car une nouvelle personne reconstruit le conteneur et obtient le même outillage. Le développement distant devient plus cohérent entre local et Codespaces. Enfin, les corrections assistées par IA deviennent reproductibles, car lint, typecheck et tests s’exécutent dans le même environnement.
Les fichiers de la configuration
Nous séparons l’application, les services et l’état de Claude Code. Cette séparation évite de monter tout le dossier personnel de la machine hôte.
| Fichier | Rôle | Points à vérifier |
|---|---|---|
.devcontainer/devcontainer.json | Point d’entrée lu par l’éditeur | remoteUser, ports, mounts, lifecycle commands |
.devcontainer/Dockerfile | Installe les outils et Claude Code | version du CLI, utilisateur non-root, paquets système |
.devcontainer/docker-compose.yml | Lance app, PostgreSQL et Redis | volumes, health checks, ports publiés |
.devcontainer/post-create.sh | Initialisation après création | lockfile, Prisma, erreurs visibles |
.claude/settings.json | Permissions Claude Code | .env, secrets, push et commandes Docker dangereuses |
devcontainer.json prêt à copier
Créez .devcontainer/devcontainer.json. Le fichier doit rester du JSON valide, donc sans commentaires.
{
"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 doit rester un utilisateur non-root. Le conteneur réduit le risque, mais le workspace est tout de même monté depuis la machine hôte. Une suppression dans /workspaces/app modifie le dépôt local. Le volume de /home/node/.claude permet de conserver la configuration Claude Code entre les rebuilds sans exposer tout le home du poste hôte.
Docker Compose, Dockerfile et postCreateCommand
Le fichier .devcontainer/docker-compose.yml lance l’application, PostgreSQL et Redis. On utilise d’abord forwardPorts; publier directement les ports de base de données via Compose n’est nécessaire que pour des outils externes.
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:
Dans le Dockerfile, nous figeons la version de Claude Code. Le 2 juin 2026, npm view @anthropic-ai/claude-code version renvoyait 2.1.160; vérifiez la version actuelle avant de l’adopter durablement.
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
Placez ensuite l’initialisation dans .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
Le script respecte le lockfile du projet et échoue franchement si l’installation est cassée. Ne lancez pas npm run dev dans postCreateCommand; ce type de processus long doit vivre dans une terminale, une task VS Code ou un service séparé.
Permissions, secrets, volumes et ports
Ne montez pas ~/.ssh, ~/.aws, ~/.config/gcloud ou un .env de production par simple confort. Le secret le plus sûr est celui qui n’entre jamais dans le conteneur. Les variables de développement peuvent pointer vers les services Compose internes; les vrais secrets doivent passer par des secrets gérés ou des jetons courts.
Les permissions projet de Claude Code peuvent être placées dans .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 *)"
]
}
}
Les volumes accélèrent le quotidien, mais ils conservent aussi les mauvais états. node_modules doit rester dans un volume Linux du conteneur, pas dans un dossier généré sur macOS ou Windows. Le volume PostgreSQL est utile, mais il faut documenter quand docker compose -f .devcontainer/docker-compose.yml down -v est autorisé.
Erreurs fréquentes et vérification
Les erreurs les plus courantes sont d’exécuter Claude Code en root, de ne pas figer la version du CLI, de monter des secrets de production, de démarrer un serveur long dans postCreateCommand et de publier les ports PostgreSQL ou Redis sans raison. Ces choix semblent pratiques au début, puis rendent les corrections impossibles à reproduire.
Après un rebuild, vérifiez node --version, npm --version, claude --version, au moins une commande de lint ou de test, puis http://localhost:3000. Assurez-vous que .env, .env.local et secrets/** ne sont pas lisibles par Claude Code et que les services internes ne sont pas exposés au-delà du nécessaire.
Pour approfondir Compose, consultez le guide Docker Compose avec Claude Code. Pour relier cette vérification au déploiement, lisez aussi le guide CI/CD Claude Code. Si votre équipe veut transformer devcontainers, CLAUDE.md, permissions et revues qualité en processus stable, la page training / consultation est le bon point de départ.
Résultat après essai
Dans un petit dépôt Next.js, les gains les plus nets venaient de trois décisions : isoler postCreateCommand dans un script, placer node_modules dans un volume de conteneur et conserver /home/node/.claude dans un volume par projet. Après rebuild, la version de Claude Code, l’installation des dépendances, la génération Prisma et le port 3000 se vérifiaient de la même façon. Le principal piège était le volume de base de données après plusieurs migrations de test. La reproductibilité vient donc du couple version fixée, secrets limités, volumes documentés et ports maîtrisés.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Échelle de sécurité des permissions Claude Code
Passer du read-only aux éditions limitées, preuves et checks de déploiement sans perdre le contrôle.
Claude Code Small PR Proof Pack : rendre les petits changements reviewables
Un pack de preuve pour PR Claude Code : diff, vérifications, URL publique, CTA et rollback.
Gate de review avant commit avec Claude Code
Review avant commit avec Claude Code : diff, build, URL publique, liens Gumroad, CTA consultation, tests manquants et fichiers hors scope.