Docker Compose — Command and Entrypoint
Every Docker image has a default command that runs when the container starts. Compose lets you override both the command and the entrypoint to customize container behavior.
How Docker Commands Work
┌──────────────────────────────────────┐
│ Container Startup │
│ │
│ ENTRYPOINT + CMD = Full Command│
│ │
│ Example (nginx): │
│ ENTRYPOINT: none │
│ CMD: ["nginx", "-g", "daemon off;"]│
│ │
│ Example (postgres): │
│ ENTRYPOINT: ["docker-entrypoint.sh"]│
│ CMD: ["postgres"] │
└──────────────────────────────────────┘
- ENTRYPOINT: The executable to run (hard to override)
- CMD: Default arguments passed to entrypoint (easy to override)
Overriding command:
The command: key overrides the CMD instruction from the Dockerfile:
services:
# Default: nginx starts and serves files
web:
image: nginx:alpine
# Override: run a custom command instead
web-custom:
image: nginx:alpine
command: nginx -g "daemon off;" -c /etc/nginx/custom.conf
# Shell form — runs through /bin/sh
debug:
image: alpine
command: sh -c "echo Hello && sleep 3600"
# Exec form — runs directly (preferred)
debug2:
image: alpine
command: ["sh", "-c", "echo Hello && sleep 3600"]
Common Use Cases
services:
# Run database with custom flags
db:
image: postgres:16
command: postgres -c shared_buffers=256MB -c max_connections=200
# Run app in dev mode
api:
build: .
command: npm run dev
# Run migrations before starting
api:
build: .
command: sh -c "npm run migrate && npm start"
Overriding entrypoint:
The entrypoint: key overrides the ENTRYPOINT instruction:
services:
# Override entrypoint to debug
db:
image: postgres:16
entrypoint: ["sh", "-c", "echo 'Container started' && exec docker-entrypoint.sh postgres"]
Warning: Overriding entrypoint: can break images that depend on their entrypoint script (like PostgreSQL, MySQL). Use command: instead when possible.
Shell Form vs Exec Form
| Form | Syntax | Shell Processing | Signal Handling |
|---|---|---|---|
| Shell | command: echo hello |
✅ Yes (sh -c) |
❌ Signals go to shell |
| Exec | command: ["echo", "hello"] |
❌ No | ✅ Signals go to process |
services:
# Shell form — supports pipes, variables, &&
app:
command: sh -c "echo $HOSTNAME && npm start"
# Exec form — better signal handling, cleaner
app:
command: ["npm", "start"]
Best practice: Use exec form for simple commands, shell form when you need pipes (|), chaining (&&), or variable expansion.
Summary
| Option | Overrides | Use When |
|---|---|---|
command: |
Dockerfile CMD | Custom arguments or dev mode |
entrypoint: |
Dockerfile ENTRYPOINT | Rarely — can break images |
| Shell form | command: npm start |
Need shell features |
| Exec form | command: ["npm", "start"] |
Clean signal handling |
Quick Reference
| Item | Detail |
|---|---|
| command: npm run dev | Override CMD for dev mode |
| command: [‘npm’, ‘start’] | Exec form — better signal handling |
| entrypoint: | Override ENTRYPOINT — use carefully |
| Shell form | Supports pipes, &&, variables |
| Exec form | Direct execution, proper signal handling |
| Best practice | Prefer command: over entrypoint: |