TLDR: Run your API and database in Docker Compose. Inject secrets with infisical run -- docker compose up. Run AI agents in a separate sandbox with only source code. No .env files on disk. Secrets exist only in container memory. AI cannot see them.
Your dev stack needs secrets. Your AI agent needs your codebase. These two must never share the same environment.
Architecture
HOST MACHINE├── Docker Compose (dev stack)│ ├── API container (secrets via Infisical)│ ├── PostgreSQL, Redis│ └── Frontend (public vars only)├── AI Sandbox (Claude Code / Codex)│ ├── Source code (mounted)│ └── NO secrets, NO env vars├── Infisical CLI (fetches secrets, injects into Docker)└── 1Password (personal passwords, SSH keys, 2FA)docker-compose.dev.yml
services: api: build: { context: ., dockerfile: Dockerfile.dev } volumes: [./apps/api/src:/app/apps/api/src] ports: ["3333:3333"] environment: - DATABASE_URL # No value = inherited from host - DATABASE_PASSWORD # Infisical populates these - STRIPE_SECRET_KEY - JWT_SECRET depends_on: [postgres, redis]
web: build: { context: ., dockerfile: Dockerfile.dev } volumes: [./apps/web/src:/app/apps/web/src] ports: ["3000:3000"] environment: - NEXT_PUBLIC_API_URL=http://localhost:3333
postgres: image: postgres:16-alpine environment: { POSTGRES_DB: myapp_dev, POSTGRES_USER: myapp, POSTGRES_PASSWORD: dev-password, } # No host ports. Only reachable by other containers on the same network.
redis: image: redis:7-alpine # No host ports. Only reachable by other containers on the same network.Starting the stack
# Infrastructure firstdocker compose -f docker-compose.dev.yml up -d postgres redis
# API with secrets injectedinfisical run --env=dev -- docker compose -f docker-compose.dev.yml up -d api
# Frontend (no secrets needed)docker compose -f docker-compose.dev.yml up -d webInfisical fetches secrets and injects them as env vars. Docker Compose passes them to the container. Nothing touches disk. See Setting up Infisical for the setup.
Common tasks
# Logsdocker compose -f docker-compose.dev.yml logs -f api
# Migrationsinfisical run --env=dev -- docker compose -f docker-compose.dev.yml exec api node ace migration:run
# Testsinfisical run --env=dev -- docker compose -f docker-compose.dev.yml exec api npm test
# Rebuildinfisical run --env=dev -- docker compose -f docker-compose.dev.yml up -d --build api
# Restart after secret rotationinfisical run --env=dev -- docker compose -f docker-compose.dev.yml restart apiThe .env.example file
Document which env vars exist. Commit to git with placeholder values. Real .env files must never exist.
DATABASE_URL=postgresql://localhost:5432/myapp_devSTRIPE_SECRET_KEY=sk_test_replace_meJWT_SECRET=replace-me