Docker Dev Setup
Create a production-grade Docker setup for any application: multi-stage Dockerfile, Compose for local development services, .dockerignore, and optional VS Code Dev Container.
When to Use
- Dockerizing an application for the first time
- Creating a multi-stage Dockerfile for smaller, secure images
- Setting up Docker Compose for local development (app + database + cache)
- Adding a
.dockerignore to speed up builds and prevent secret leaks
- Optimizing an existing Docker image (size, build speed, security)
- Creating a Dev Container for VS Code / GitHub Codespaces
- Debugging Docker build failures or runtime issues
Tools Used
- Read — inspect existing project files (package.json, requirements.txt, go.mod, existing Dockerfiles)
- Write — create Dockerfile, compose.yaml, .dockerignore, devcontainer.json
- Edit — modify existing Docker configuration
- Bash — run docker build, docker compose, check image size
- Glob — find project entry points, existing Docker files
- Grep — detect frameworks, dependencies, existing Docker usage
Bundled Files
docker-dev-setup/
├── references/
│ ├── dockerfile-patterns.md # Multi-stage builds, caching, security
│ ├── compose-patterns.md # Services, health checks, volumes, networking
│ └── troubleshooting.md # Common errors and fixes
└── templates/
├── Dockerfile.node # Node.js/TypeScript multi-stage
├── Dockerfile.python # Python multi-stage
├── Dockerfile.go # Go multi-stage (scratch/distroless)
├── compose.yaml # Local dev stack (app + postgres + redis)
├── dockerignore # Universal .dockerignore template
└── devcontainer.json # VS Code Dev Container config
Workflow
Follow these phases in order. Stop after each phase to confirm with the user before continuing.
Phase 1: Discover
Goal: Understand the project stack and what needs containerizing.
Check for an existing project:
Read package.json → Node.js/TypeScript (check for build script, entry point)
Read requirements.txt → Python (check for gunicorn/uvicorn)
Read go.mod → Go (check module path)
Read pyproject.toml → Python (check for poetry/uv)
Glob Dockerfile* → existing Docker setup
Glob compose* → existing Compose files
Glob .devcontainer/** → existing Dev Container
Identify the key details:
- Language/runtime: Node.js, Python, Go, or other
- Package manager: npm/yarn/pnpm, pip/poetry/uv, go mod
- Build step: Does the app need compilation? (TypeScript, Go, etc.)
- Entry point: What command starts the app? (node server.js, gunicorn, ./binary)
- Services needed: Database (PostgreSQL, MySQL, SQLite), cache (Redis), queue (RabbitMQ), etc.
- Existing Docker files: Any Dockerfile or compose.yaml already present?
Choose the appropriate template from templates/:
- Node.js/TypeScript →
Dockerfile.node
- Python →
Dockerfile.python
- Go →
Dockerfile.go
- Other → Use
references/dockerfile-patterns.md to build from scratch
STOP. Confirm the stack, entry point, and which services the user needs.
Phase 2: Dockerfile
Goal: Create a production-grade, multi-stage Dockerfile.
Read the appropriate template from templates/ and references/dockerfile-patterns.md.
Create the Dockerfile at the project root. Every Dockerfile should include:
- Multi-stage build: Separate build and runtime stages
- Layer caching: Copy dependency files BEFORE source code
- Minimal base image: Use
-alpine or -slim variants (not full ubuntu or node:22)
- Non-root user: Create and switch to a non-root user
- Health check: Add
HEALTHCHECK for HTTP services
- Signal handling: Use
dumb-init or tini for Node.js (PID 1 problem)
Create .dockerignore from templates/dockerignore. Customize for the project's language.
Key rules from references/dockerfile-patterns.md:
- Use
COPY not ADD (unless extracting tar archives)
- Use exec form for CMD:
CMD ["node", "server.js"] not CMD node server.js
- Combine
apt-get update && apt-get install && rm -rf /var/lib/apt/lists/* in one RUN
- Pin base image versions:
node:22-alpine not node:latest
- Use
npm ci not npm install in Docker builds
- For Go:
CGO_ENABLED=0 for static binaries that run on scratch
STOP. Review the Dockerfile with the user. Verify it builds: docker build -t app .
Phase 3: Compose
Goal: Set up Docker Compose for local development.
Read references/compose-patterns.md and templates/compose.yaml.
Create compose.yaml (not docker-compose.yml — Compose v2 convention) at the project root:
- App service: Build from local Dockerfile, bind-mount source for hot reload, forward ports
- Database service: PostgreSQL/MySQL with health check, named volume for data persistence
- Cache service (if needed): Redis with health check
- depends_on with condition: Use
condition: service_healthy so the app waits for services to be ready
Health check patterns for common services:
# PostgreSQL
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# MySQL
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
Key rules:
- Do NOT include a
version: key — it's deprecated in Compose v2
- Use named volumes for database data (not bind mounts)
- Use bind mounts for application source code (enables hot reload)
- Set environment variables via
environment: block, not .env files in the image
- Use
restart: unless-stopped for infrastructure services
STOP. Confirm the Compose setup. Verify it starts: docker compose up
Phase 4: Dev Container (optional)
Goal: Add VS Code Dev Container support for reproducible dev environments.
Only do this phase if the user wants Dev Container support. Skip otherwise.
Read templates/devcontainer.json.
Create .devcontainer/devcontainer.json with:
- Base image or Dockerfile reference
- VS Code extensions to auto-install
- Port forwarding for the app and services
postCreateCommand for dependency installation
remoteUser set to non-root
- Features for common tools (Docker-in-Docker, CLI tools)
If using Compose, reference the compose file:
{
"dockerComposeFile": "../compose.yaml",
"service": "app",
"workspaceFolder": "/app"
}
STOP. Confirm the Dev Container config. Test by reopening in container.
Troubleshooting Quick Reference
Read references/troubleshooting.md for detailed solutions.
| Symptom |
Likely Cause |
Quick Fix |
COPY failed: file not found |
File excluded by .dockerignore or wrong path |
Check .dockerignore, verify build context |
| Image is 1GB+ |
Full base image, no multi-stage |
Switch to -alpine/-slim, add multi-stage |
| Container exits immediately |
PID 1 signal handling, missing CMD |
Use dumb-init, check CMD/ENTRYPOINT |
port is already allocated |
Port conflict on host |
Change host port in compose or stop other containers |
| Build is slow despite no code changes |
Cache invalidated by COPY order |
Copy dependency files before source code |
depends_on not waiting for DB |
Missing health check condition |
Add condition: service_healthy |
| Volume permission denied |
Non-root user can't write to volume |
Use --chown in COPY, or fix volume ownership |
Architecture Notes
- Multi-stage builds are the single most impactful optimization. Build stage has compilers/tools; runtime stage has only the artifact. Typical 80-99% size reduction.
- Layer caching depends on instruction order. Put things that change rarely (system packages) before things that change often (source code). Copy dependency lock files before source code.
- Compose v2 uses
docker compose (space, not hyphen). No version: key needed. Health checks + depends_on: condition: service_healthy replaces the old wait-for-it.sh scripts.
- Dev Containers are a spec, not a VS Code feature. They work in Codespaces, DevPod, Gitpod, and any IDE that supports the spec. The
.devcontainer/ directory travels with the repo.
- .dockerignore is not optional. Without it,
.git/ alone can add hundreds of MB to the build context, and .env files may leak secrets into the image.
Output Summary
After completing all phases, the user should have:
1---2name: docker-dev-setup3description: Containerize an application with a production-grade Dockerfile, Docker Compose for local development, and optional Dev Container configuration. Use for: Dockerizing apps, multi-stage builds, Compose local dev stacks, .dockerignore, image size optimization, dev containers. Triggers: docker, dockerfile, compose, container, containerize, dockerize, docker-compose, devcontainer, dev container, docker setup, docker image, docker build.4---5
6# Docker Dev Setup
7
8Create a production-grade Docker setup for any application: multi-stage Dockerfile, Compose for local development services, .dockerignore, and optional VS Code Dev Container.
9
10## When to Use
11
12- Dockerizing an application for the first time
13- Creating a multi-stage Dockerfile for smaller, secure images
14- Setting up Docker Compose for local development (app + database + cache)
15- Adding a `.dockerignore` to speed up builds and prevent secret leaks
16- Optimizing an existing Docker image (size, build speed, security)
17- Creating a Dev Container for VS Code / GitHub Codespaces
18- Debugging Docker build failures or runtime issues
19
20## Tools Used
21
22- **Read** — inspect existing project files (package.json, requirements.txt, go.mod, existing Dockerfiles)
23- **Write** — create Dockerfile, compose.yaml, .dockerignore, devcontainer.json
24- **Edit** — modify existing Docker configuration
25- **Bash** — run docker build, docker compose, check image size
26- **Glob** — find project entry points, existing Docker files
27- **Grep** — detect frameworks, dependencies, existing Docker usage
28
29## Bundled Files
30
31```
32docker-dev-setup/
33├── references/
34│ ├── dockerfile-patterns.md # Multi-stage builds, caching, security
35│ ├── compose-patterns.md # Services, health checks, volumes, networking
36│ └── troubleshooting.md # Common errors and fixes
37└── templates/
38 ├── Dockerfile.node # Node.js/TypeScript multi-stage
39 ├── Dockerfile.python # Python multi-stage
40 ├── Dockerfile.go # Go multi-stage (scratch/distroless)
41 ├── compose.yaml # Local dev stack (app + postgres + redis)
42 ├── dockerignore # Universal .dockerignore template
43 └── devcontainer.json # VS Code Dev Container config
44```
45
46## Workflow
47
48Follow these phases in order. **Stop after each phase** to confirm with the user before continuing.
49
50---
51
52### Phase 1: Discover
53
54**Goal:** Understand the project stack and what needs containerizing.
55
561. Check for an existing project:
57 ```
58 Read package.json → Node.js/TypeScript (check for build script, entry point)
59 Read requirements.txt → Python (check for gunicorn/uvicorn)
60 Read go.mod → Go (check module path)
61 Read pyproject.toml → Python (check for poetry/uv)
62 Glob Dockerfile* → existing Docker setup
63 Glob compose* → existing Compose files
64 Glob .devcontainer/** → existing Dev Container
65 ```
66
672. Identify the key details:
68 - **Language/runtime**: Node.js, Python, Go, or other
69 - **Package manager**: npm/yarn/pnpm, pip/poetry/uv, go mod
70 - **Build step**: Does the app need compilation? (TypeScript, Go, etc.)
71 - **Entry point**: What command starts the app? (node server.js, gunicorn, ./binary)
72 - **Services needed**: Database (PostgreSQL, MySQL, SQLite), cache (Redis), queue (RabbitMQ), etc.
73 - **Existing Docker files**: Any Dockerfile or compose.yaml already present?
74
753. Choose the appropriate template from `templates/`:
76 - Node.js/TypeScript → `Dockerfile.node`
77 - Python → `Dockerfile.python`
78 - Go → `Dockerfile.go`
79 - Other → Use `references/dockerfile-patterns.md` to build from scratch
80
81> **STOP.** Confirm the stack, entry point, and which services the user needs.
82
83---
84
85### Phase 2: Dockerfile
86
87**Goal:** Create a production-grade, multi-stage Dockerfile.
88
891. Read the appropriate template from `templates/` and `references/dockerfile-patterns.md`.
90
912. Create the Dockerfile at the project root. Every Dockerfile should include:
92 - **Multi-stage build**: Separate build and runtime stages
93 - **Layer caching**: Copy dependency files BEFORE source code
94 - **Minimal base image**: Use `-alpine` or `-slim` variants (not full `ubuntu` or `node:22`)
95 - **Non-root user**: Create and switch to a non-root user
96 - **Health check**: Add `HEALTHCHECK` for HTTP services
97 - **Signal handling**: Use `dumb-init` or `tini` for Node.js (PID 1 problem)
98
993. Create `.dockerignore` from `templates/dockerignore`. Customize for the project's language.
100
1014. Key rules from `references/dockerfile-patterns.md`:
102 - Use `COPY` not `ADD` (unless extracting tar archives)
103 - Use exec form for CMD: `CMD ["node", "server.js"]` not `CMD node server.js`
104 - Combine `apt-get update && apt-get install && rm -rf /var/lib/apt/lists/*` in one RUN
105 - Pin base image versions: `node:22-alpine` not `node:latest`
106 - Use `npm ci` not `npm install` in Docker builds
107 - For Go: `CGO_ENABLED=0` for static binaries that run on `scratch`
108
109> **STOP.** Review the Dockerfile with the user. Verify it builds: `docker build -t app .`
110
111---
112
113### Phase 3: Compose
114
115**Goal:** Set up Docker Compose for local development.
116
1171. Read `references/compose-patterns.md` and `templates/compose.yaml`.
118
1192. Create `compose.yaml` (not `docker-compose.yml` — Compose v2 convention) at the project root:
120 - **App service**: Build from local Dockerfile, bind-mount source for hot reload, forward ports
121 - **Database service**: PostgreSQL/MySQL with health check, named volume for data persistence
122 - **Cache service** (if needed): Redis with health check
123 - **depends_on with condition**: Use `condition: service_healthy` so the app waits for services to be ready
124
1253. Health check patterns for common services:
126 ```yaml
127 # PostgreSQL
128 healthcheck:
129 test: ["CMD-SHELL", "pg_isready -U postgres"]
130 interval: 10s
131 timeout: 5s
132 retries: 5
133
134 # Redis
135 healthcheck:
136 test: ["CMD", "redis-cli", "ping"]
137 interval: 10s
138 timeout: 5s
139 retries: 5
140
141 # MySQL
142 healthcheck:
143 test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
144 interval: 10s
145 timeout: 5s
146 retries: 5
147 ```
148
1494. Key rules:
150 - Do NOT include a `version:` key — it's deprecated in Compose v2
151 - Use named volumes for database data (not bind mounts)
152 - Use bind mounts for application source code (enables hot reload)
153 - Set environment variables via `environment:` block, not `.env` files in the image
154 - Use `restart: unless-stopped` for infrastructure services
155
156> **STOP.** Confirm the Compose setup. Verify it starts: `docker compose up`
157
158---
159
160### Phase 4: Dev Container (optional)
161
162**Goal:** Add VS Code Dev Container support for reproducible dev environments.
163
1641. Only do this phase if the user wants Dev Container support. Skip otherwise.
165
1662. Read `templates/devcontainer.json`.
167
1683. Create `.devcontainer/devcontainer.json` with:
169 - Base image or Dockerfile reference
170 - VS Code extensions to auto-install
171 - Port forwarding for the app and services
172 - `postCreateCommand` for dependency installation
173 - `remoteUser` set to non-root
174 - Features for common tools (Docker-in-Docker, CLI tools)
175
1764. If using Compose, reference the compose file:
177 ```json
178 {
179 "dockerComposeFile": "../compose.yaml",
180 "service": "app",
181 "workspaceFolder": "/app"
182 }
183 ```
184
185> **STOP.** Confirm the Dev Container config. Test by reopening in container.
186
187---
188
189## Troubleshooting Quick Reference
190
191Read `references/troubleshooting.md` for detailed solutions.
192
193| Symptom | Likely Cause | Quick Fix |
194|---------|-------------|-----------|
195| `COPY failed: file not found` | File excluded by `.dockerignore` or wrong path | Check `.dockerignore`, verify build context |
196| Image is 1GB+ | Full base image, no multi-stage | Switch to `-alpine`/`-slim`, add multi-stage |
197| Container exits immediately | PID 1 signal handling, missing CMD | Use `dumb-init`, check CMD/ENTRYPOINT |
198| `port is already allocated` | Port conflict on host | Change host port in compose or stop other containers |
199| Build is slow despite no code changes | Cache invalidated by COPY order | Copy dependency files before source code |
200| `depends_on` not waiting for DB | Missing health check condition | Add `condition: service_healthy` |
201| Volume permission denied | Non-root user can't write to volume | Use `--chown` in COPY, or fix volume ownership |
202
203## Architecture Notes
204
205- **Multi-stage builds** are the single most impactful optimization. Build stage has compilers/tools; runtime stage has only the artifact. Typical 80-99% size reduction.
206- **Layer caching** depends on instruction order. Put things that change rarely (system packages) before things that change often (source code). Copy dependency lock files before source code.
207- **Compose v2** uses `docker compose` (space, not hyphen). No `version:` key needed. Health checks + `depends_on: condition: service_healthy` replaces the old `wait-for-it.sh` scripts.
208- **Dev Containers** are a spec, not a VS Code feature. They work in Codespaces, DevPod, Gitpod, and any IDE that supports the spec. The `.devcontainer/` directory travels with the repo.
209- **.dockerignore** is not optional. Without it, `.git/` alone can add hundreds of MB to the build context, and `.env` files may leak secrets into the image.
210
211## Output Summary
212
213After completing all phases, the user should have:
214
215- [ ] Multi-stage Dockerfile at project root
216- [ ] `.dockerignore` customized for the project stack
217- [ ] `compose.yaml` with app + services, health checks, named volumes
218- [ ] Working `docker compose up` that starts the full local stack
219- [ ] (Optional) `.devcontainer/devcontainer.json` for VS Code / Codespaces