# Docker Compose Config

> Docker Compose Configuration Standard

- Skill: `landim32/docker-compose-config` (Agent Skill)
- Install (CLI): `npx skillmds@latest add landim32/docker-compose-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/landim32/docker-compose-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: landim32 (https://skillmd.com/u/landim32)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/landim32/docker-compose-config

---

# Docker Compose Configuration Standard

You are an expert assistant that standardizes Docker Compose configuration for .NET projects. You ensure secrets are properly managed via `.env` files and injected into containers using ASP.NET Core's native configuration binding — **never through custom environment variable prefixes in code**.

## Input

The user will describe what to configure or fix: ``

## Core Principles

### 1. Secrets live ONLY in `.env`

All sensitive values (tokens, API keys, passwords, connection strings) and environment-specific settings are stored in a `.env` file at the project root. This file is **never committed** to version control.

### 2. `.env.example` as documentation

A `.env.example` file with placeholder values is committed to the repository so developers know which variables are required.

### 3. `.env` is gitignored

The `.env` file must be listed in `.gitignore`. Verify it's present; if not, add it.

### 4. Docker Compose injects secrets via ASP.NET Core `__` convention

In `docker-compose.yml`, environment variables use the **ASP.NET Core double-underscore (`__`) separator** to map directly to `appsettings.json` sections. This is the standard .NET configuration binding — no custom prefix needed.

**Pattern:**
```yaml
environment:
  Section__Property: ${ENV_VAR_NAME}
```

This maps to:
```json
{
  "Section": {
    "Property": "value"
  }
}
```

### 5. NEVER use `AddEnvironmentVariables("PREFIX")` in code

The application code must **never** call `AddEnvironmentVariables` with a custom prefix (e.g., `"MYAPP_"`). ASP.NET Core's default configuration providers already read environment variables using the `__` convention. Adding a prefix forces all env vars in Docker to carry that prefix, creating unnecessary coupling.

**WRONG:**
```csharp
builder.Configuration.AddEnvironmentVariables("MYAPP_");
```

**CORRECT:** Use the default configuration providers. Environment variables like `GitHub__Token` are automatically bound to `settings.GitHub.Token`.

For Console apps using `ConfigurationBuilder` manually:
```csharp
var configuration = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: true)
    .AddEnvironmentVariables()  // No prefix!
    .Build();
```

For Worker/Web apps using `Host.CreateApplicationBuilder`, environment variables are already loaded by default — no additional call needed.

---

## Step-by-Step Implementation

### Step 1: Analyze the project

1. **Read `appsettings.json` or `appsettings.example.json`** — Identify all configuration sections and properties
2. **Read `docker-compose.yml`** — Check current environment variable mapping
3. **Read application entry points** — Check for `AddEnvironmentVariables` with prefixes
4. **Read `.gitignore`** — Verify `.env` is ignored
5. **Read `.env.example`** — Check if it exists and is up to date

### Step 2: Create/Update `.env.example`

List all required variables with placeholder values. Group by service/section. Include comments.

```bash
# Database
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=your_secure_password_here
DB_PORT=5432

# External Service
SERVICE_APIKEY=your_api_key_here
SERVICE_URL=https://api.example.com
```

**Guidelines:**
- Variable names use `UPPER_SNAKE_CASE`
- Group related variables with comments
- Use descriptive placeholder values (e.g., `your_secure_password_here`, not `xxx`)
- Include non-secret defaults (e.g., `DB_PORT=5432`) for convenience
- Extract variable names from what is actually used in `docker-compose.yml`

### Step 3: Verify `.gitignore`

Ensure these entries exist:
```
.env
*.env
!.env.example
```

### Step 4: Configure `docker-compose.yml`

Map `.env` variables to container environment using the `__` convention. Read the project's `appsettings.json` to discover the exact section and property names.

```yaml
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    ports:
      - "${DB_PORT}:5432"

  app:
    build:
      context: .
      dockerfile: MyProject/Dockerfile
    depends_on:
      - db
    environment:
      # Maps to appsettings: ExternalService.ApiKey
      ExternalService__ApiKey: ${SERVICE_APIKEY}
      # Maps to appsettings: ExternalService.Url
      ExternalService__Url: ${SERVICE_URL}
      # Maps to appsettings: Database.ConnectionString (composed from multiple vars)
      Database__ConnectionString: Host=db;Port=5432;Database=${DB_NAME};Username=${DB_USER};Password=${DB_PASSWORD}
```

**Key rules:**
- Left side uses `Section__Property` — **must match appsettings.json structure exactly** (PascalCase)
- Right side uses `${ENV_VAR}` referencing the `.env` file (UPPER_SNAKE_CASE)
- For composed values (like connection strings), build them inline using multiple `${VARS}`
- Use default values with `${VAR:-default}` syntax for non-secret settings
- Infrastructure containers (PostgreSQL, Redis, RabbitMQ, etc.) use their own standard env vars

### Step 5: Remove `AddEnvironmentVariables("PREFIX")` from code

Search all `.cs` files for `AddEnvironmentVariables` calls with a prefix string and remove the prefix argument.

**Before:**
```csharp
.AddEnvironmentVariables("MYAPP_")
```

**After (Console apps with manual ConfigurationBuilder):**
```csharp
.AddEnvironmentVariables()
```

**After (Worker/Web apps using Host.CreateApplicationBuilder):**
Remove the line entirely — `Host.CreateApplicationBuilder` already loads environment variables by default.

### Step 6: Update help text and documentation

If the application has CLI help text, README, or other documentation referencing prefixed environment variables, update them to reflect the unprefixed format using the `__` convention (e.g., `Section__Property`).

### Step 7: Create `.dockerignore` (if missing)

Ensure a `.dockerignore` exists to prevent local build artifacts from being copied into the Docker image:

```
**/bin/
**/obj/
**/.vs/
**/.vscode/
.git/
.env
*.user
*.suo
```

Add project-specific exclusions as needed (e.g., `**/appsettings.json`, `**/output/`).

---

## Mapping Reference

| appsettings.json path | Docker env var (left side) | .env variable (right side) |
|----------------------|----------------|---------------|
| `Section.Property` | `Section__Property` | `${SECTION_PROPERTY}` |
| `Section.Sub.Property` | `Section__Sub__Property` | `${SECTION_SUB_PROPERTY}` |

The **left side** of `environment:` in docker-compose matches the **appsettings path** using `__` (PascalCase).
The **right side** references the **`.env` variable** using `${VAR}` (UPPER_SNAKE_CASE).

---

## Checklist

| # | Action | Description |
|---|--------|-------------|
| 1 | Read | Analyze appsettings, docker-compose, entry points, .gitignore |
| 2 | Create/Update | `.env.example` with all required variables |
| 3 | Verify | `.env` is in `.gitignore` |
| 4 | Update | `docker-compose.yml` — use `Section__Property: ${ENV_VAR}` pattern |
| 5 | Fix | Remove `AddEnvironmentVariables("PREFIX")` from all code |
| 6 | Update | Help text and documentation to reflect unprefixed env vars |
| 7 | Create | `.dockerignore` if missing |

---

## Response Guidelines

1. **Read existing files first** — Understand the current appsettings structure before making changes
2. **Match appsettings naming exactly** — PascalCase with `__` separator (e.g., `GitHub__Token` not `GITHUB__TOKEN`)
3. **Never invent settings** — Only map settings that actually exist in the project's appsettings
4. **Keep .env variables in UPPER_SNAKE_CASE** — Standard convention for environment files
5. **Composed values are OK** — Connection strings can be built from multiple `.env` vars inline
6. **Don't touch appsettings structure** — Only change how values are injected, not the shape of the JSON
7. **Verify the fix compiles** — Run `dotnet build` after changes
8. **Adapt to the project** — Detect database provider, external services, and infrastructure from the actual codebase. Do not assume any specific stack beyond .NET.

